| Re: IDL Object for creating a Singleton [message #12125 is a reply to message #11979] |
Mon, 22 June 1998 00:00  |
Phillip & Suzanne
Messages: 31 Registered: June 1998
|
Member |
|
|
J.D. Smith wrote:
>
> David Fanning wrote:
>>
>> Phillip David (pdavid@earthling.net) writes:
>>
>>> I've been doing a fair amount of reading on OO design and methodology. One of
>>> the books I've had pointed out to me was 'Design Patterns', which deals with
>>> OO algorithm design quite nicely. One of the patterns the authors describe is
>>> a Singleton -- A class for which only one instance exists. If the sole
>>> instance exists, the constructor function (object's init function in IDL) will
>>> return a reference to the existing object. If none exists, a new object is
>>> created and returned.
>>>
>>> This structure is particularly useful when there is no reason to have multiple
>>> objects around. I am trying to create a user preferences object that fits
>>> this criteria very nicely. I'd like to be able to store user preferences for
>>> screen size in an object. If that object exists, other screens can size
>>> themselves appropriately. The book gives sample C++ code that relies on class
>>> variables and class methods (i.e., not associated with a specific instance of
>>> the object, but with the object itself). IDL doesn't seem to have any way to
>>> do something similar. Does anyone know of a way to do this?
>>>
>>> Is there a better way to achieve the techniques of class variables and class methods?
>>
>> Humm. Objects are turning out to be not only to be fun and powerful to
>> program, but synchronistic as well. This is the second time in two
>> days the _Design Patterns_ book (which I have not seen or read) was
>> mentioned to me and in an almost identical context. I was talking
>> to a friend about writing a "lurker" object, a singleton object like
>> Phillip's screen preferences object, that lurks in the background
>> waiting for something to happen. In this case, I wanted to
>> update all the open windows when a color table was changed on a
>> 24-bit display.
>>
>> Cheers,
>
> I think you've both run head-on into the limits of IDL's OO
> implementation. The foremost among these is the lack of controllable
> access. All class members are equivalent to "protected" -- visible to a
> class plus any derived classes. Especially frustrating is the absence
> of public data members, which requires one to set up GetProperty and
> SetProperty methods which do *nothing* other than access otherwise
> "public" data.
I had already pretty much figured this out. I wanted to see if other people
could come up with a better implementation than my own for this, though. What
we really need in this instance is a "class variable" ("static" is the C++
term for it), which is a single variable available to all instances of a
class. This variable can be used for such information as a count of the
number of objects of this type currently instantiated or, in the case of a
singleton, the object reference to the only instance of the class.
> Protected class methods, although less frustrating, can limit the amount
> of cooperative programming possible for large projects (since no
> mechanism is provided to prevent accidental reliance on internal, and
> therefore potentially changing, class implementation).
>
> But one must keep in mind that RSI wanted to provide the basic OO
> functionality, not a totally robust OO environment. I think they did an
> O.K. job with this. Polymorphism is well-implemented since all methods
> are "virtual protected", and all objects (read object references) are
> the equivalent of object pointers in C++ ... there is no such concept as
> static typing of a method (just as there is no concept of static typing
> of a variable) in IDL. Encapsulation, though rigid, accomplishes the
> basics of the principle.
Thanks for that perspective.
> In any case, as to your specific problem, I haven't seen the book you
> reference, but I'd bet they achieve the "singleton" functionality with a
> static data member -- a variable which is shared by all instances of the
> defining class, but only initialized once. There is no comparable
> functionality in IDL. I believe the only way to implement this *is*
> with a common block (uhgg ... but remember that XManager, everybody's
> favorite procedure, is implemented with a bunch of common blocks).
<Nice singleton generator code omitted>
I hadn't thought of using a singleton generator, and was instead concerned
with the way to generate just a single instance of the singleton class. This
is a neat trick that I'll have to remember. Even the C++ example in "Design
Patterns" (a truly GREAT book on OO techniques!) had to make the constructor a
protected function, and create a class method (i.e., static) that checked
whether the static instance variable was initialized. If it was, the variable
was returned. If not, the constructor was called by the class variable, and
the instance reference updated.
In IDL, there are no such things as either class (static) variables or
methods. As a result, I've adopted the following way of handling these things:
For class variables, I define a common block <object>_static which has my
static variables inside of it. The only reference to this common block is
within my object or other routines found within the same file as my object.
Since IDL's object model only works on objects, it cannot use a static method
either. As a result, I simply add non-object routines into the same file as
my object is defined in, and use these as the structure I want. For this
particular project, I defined a file 'GetPreferences.pro', which had the
following structure:
----------- Start of sample source code -------------------
pro Preferences::GetSize
pro Preferences::Init, caller
if caller NE 'GetPreferences' then begin
ok = Widget_Message(/Error, $
'Preference objects can only be created by the GetPreferences routine.')
return, 0 ; failure
endif
;----------------------------------------------------------- -------------------
; I store my preferences in a file. If they're present, I read them in
when my
; preferences object gets initialized. I'm not including the code for this
; because it's not relevant. However, if the variables XSize and YSize are set
; to 0, I call the Device, Get_Screen_Size=sizes to get standard sizes.
;----------------------------------------------------------- -------------------
return, 1 ; success
end
pro Preferences__Define
struct = {PREFERENCES, XSize=0, YSize=0}
end
function GetPreferences
;----------------------------------------------------------- -------------------
; This is a 'static' function for the Preferences class. Notice that unless
; this function is called, the preferences object code is never even compiled
; unless it's compiled explicitly. This prevents the inadvertant call to a
; preferences object prior to invoking a GetPreferences routine. The check
; for the proper caller in the init function for the preferences object does
; the rest of the protection I can create. While it's not entirely foolproof
; this method does provide substantial protection.
;
; My main concern here is that this method is not technically a part of the
; class, but as JD points out, this may not be possible due to limitations
; of the object nature of IDL.
;----------------------------------------------------------- -------------------
common Preferences_Static, preferences
prefsSize = size(preferences)
if prefsSize(prefsSize(0)+1) EQ OBJECT then return, preferences
preferences = Obj_New('Preferences', 'GetPreferences')
return, preferences
end
---------- end of sample source code -------------
What do you think of this as a simpler approach when you just need a single Singleton?
I was hoping for something more elegant than common blocks, but I guess that's
what I'll continue to use. Thanks for your inputs. I'll try to continue
posting interesting OO ideas as I think of them.
By the way, David, what happened with the Direct Graphics as objects
techniques? I never saw more about them, but I haven't had proper newsgroup
access for a while.
Phillip
|
|
|
|