Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Tight / loose coupling
Message
From
03/11/2004 15:01:31
Al Doman (Online)
M3 Enterprises Inc.
North Vancouver, British Columbia, Canada
 
General information
Forum:
Visual FoxPro
Category:
Object Oriented Programming
Miscellaneous
Thread ID:
00957392
Message ID:
00957786
Views:
15
>Hi Al,
>
>Your code is almost -exactly- what I do in the Init() method (my property is called ioCommon).
>
>Sure, it's --possible-- to do this in the Load() method. However, I don't understand what benefit(s) might occur from this change -- and I seem to remember having difficulty successfully altering object properties before the Init() of that object begins executing. Maybe that's been fixed, but still...
>
>Also, wouldn't it cause an issue if the Init() fails, since the oToolbox object doesn't actually exist until the Init() finishes? (BTW, in the proposed oToolbox.Init(), I wouldn't instantiate oToolbox.ioCommon unless the default Init() behavior completed successfully.)
>
>I suppose I could augment the Unload() to be sure that the ioCommon object reference has been released -- but then, does the Unload() always fire if the Init() fails? Sounds a bit like a deeper rat's nest to me...

Hmm, I have no idea how your code works in detail. My thought was, .Init() fires after all member objects are created. If creation of oToolbox member objects depends on the availability of ioCommon, then instantiating ioCommon in oToolbox.Init won't do it, but .Load might, which fires before any member objects are created.

As for details on how to handle .Init() failure, whether .Unload() gets called etc. depends on exactly what you're doing. The Coverage Profiler/Log might be handy in testing this.

I can think of 4 approaches to your general question:

1. Eliminate any dependency on external code by copy/pasting ioCommon properties/methods into any new class. This VB6-style approach completely breaks object orientation. However, it makes testing simple - you can test the class outside your application. Also, any such class is modular and easier to add to a "foreign" project. I wouldn't recommend this as I think there are probably better ways to handle it.

2. Instantiate oCommon as required as we've discussed above. If this can be made to work it's also modular and gains OO advantages.

3. Another option you mentioned was to instantiate ioCommon in the Application object and have it available globally e.g.
goApp.ioCommon = CREATEOBJECT( ... )
This approach basically has the pluses and minuses of PUBLIC variables:

- potentially higher performance if you don't have to create/destroy ioCommon a bunch of times
- warm fuzzy feeling of always having ioCommon.SomeMethod() available no matter where you are, just like a built-in VFP function or command

But, as you point out you've then coupled your toolbox to your app class. Your code will be littered with "hard-coded" references to goApp.ioCommon.SomeMethod(), and you won't be able to test oToolbox outside the context of your app. Any other project that wants to use oToolBox needs to create ioCommon in advance. This creates a two-way dependency with increased maintenance/documentation issues.

Another significant issue is if you allow multiple instances of child forms etc. they can't update any properties of a single global ioCommon without running into concurrency issues.

3a. You could potentially clean up your oToolbox code with something like this:
* Create "global" ioCommon:
goApp.ioCommon = CREATEOBJECT("CommonClass")

* Pass object reference to Toolbox when it's created:
oToolBox = CREATEOBJECT("ToolboxClass", goApp.ioCommon)
* could also use a parameter object

* oToolbox.Init():
LPARAMETERS tioCommon

DODEFAULT

* Update oToolbox custom property:
This.ioCommon = tioCommon

* Now you can use a more generic reference This.ioCommon.SomeMethod()/SomeProperty in your oToolbox methods
However, this still requires that ioCommon be instantiated prior to creating oToolbox. And this approach has the limitation that the passed parameter must come into .Init.

3b. Another possibility is to add a custom property to _SCREEN e.g.
=ADDPROPERTY("_Screen", "ioCommon", CREATEOBJECT("CommonClass"))
Then your oToolbox code can generically reference _SCREEN.ioCommon.SomeMethod()/SomeProperty

4. Another potentially elegant approach would be to simply make oToolBox a subclass of ioCommon. But, you say, ioCommon is CUSTOM, and oToolbox must be CONTAINER, FORM, etc. OK then, make a cntCommon or frmCommon class, and subclass that to make oToolbox. If you need the ioCommon PEMs in different class types, you've got a class architecture challenge :)

5. While I know nothing about them, I understand some of the more advanced commercial frameworks use what's called an "abstract factory" when managing these types of issues. It might be worth checking this concept out for ideas.
Regards. Al

"Violence is the last refuge of the incompetent." -- Isaac Asimov
"Never let your sense of morals prevent you from doing what is right." -- Isaac Asimov

Neither a despot, nor a doormat, be

Every app wants to be a database app when it grows up
Previous
Reply
Map
View

Click here to load this message in the networking platform