Scott Scovell on Visual FoxPro

Friday, January 06, 2006

Decorating with This_Access

Lately I have been busy coding VFP Solution Explorer, but I thought I would take a short break (don't tell Craig) to share this with you.
I had a situation(s) where I needed to sub-class a non-sub-classable(?) object, like a COM object. I naturally started to implement a decorator pattern but was faced with a mountain of tedious coding to implement the COM objects' interface (properties, events, and methods) even using the object browser to generate the basic class definition.
Having never really used the This_Access method in anger before, I decided to have a second look. This saved me loads of time as it relived the need to implement all those PEMs I was not really interested in.
Here is a simplified example of how I used the This_Access method as a shortcut for my decorator class.

* Set this constant to an existing project you have somewhere

#Define PROJECT_FILE    "MyProjectFile.pjx"


Local oMyProject As MyProject


* Create an instance of our project class passing the project file to the Init method.

oMyProject = NewObject("MyProject", "", "", PROJECT_FILE)


* Display some project properties to the desktop

? oMyProject.HomeDir

? oMyProject.Files.Count


* Call our Close method so we can execute our code before and after the project closes.





Define Class MyProject As Custom


      IFoxProject = Null


      Function Init(lpcProjectFile As String)


            * Check if project is open

            If Type([Application.Projects("] + lpcProjectFile + [")]) = "U"

                  * Open project

                  Modify Project (lpcProjectFile) NoWait Save NoShow



            * Set a reference to the project object

            This.IFoxProject = Application.Projects(lpcProjectFile)




      Function This_Access(lpcMemberName As String)


            * Check if we wish to handle this or just pass it on to the IFoxProject object

            If Not InList(lpcMemberName, "ifoxproject", "build", "close")


                  * Check we have a reference to the project object

                  If Not IsNull(This.IFoxProject)

                        Return This.IFoxProject





            * Return the reference to this class

            Return This




      Function Close()


            *** Write code or raise a before close event here ***




            *** Write code or raise an after close event here ***




      Function Build(   lpcOutputName As String, lpnBuildAction As Integer,;

                        lpbRebuildAll As Boolean, lpbShowErrors As Boolean,;

                        lpbBuildNewGUIDs As Boolean)


            *** Write code or raise a before build event here ***


            This.IFoxProject.Build( lpcOutputName As String, lpnBuildAction As Integer,;

                                   lpbRebuildAll As Boolean, lpbShowErrors As Boolean,;

                                   lpbBuildNewGUIDs As Boolean)


            *** Write code or raise an after build event here ***






As you can see from the code, I have defined my project decorator class with only those members I need to extend (the Close and Build methods in the example). In the This_Access method, I check at runtime what member is being accessed (or assigned) and "switch" between returning my object instance and returning the object instance I am decorating.
The attractiveness of this approach is the amount of code required when only a few PEMs need to be sub-classed. When new requirements present, new PEMs can be added to your class and those member names added to the list in This_Access. (you could even use PEMSTATUS() to test if the member name parameter is defined on your class and never have to touch the This_Access again).
Further benefits to this design allows the interface your decorating (sub-classing) to extend with out breaking your code (excluding member name conflicts and changes to the existing interface, but those are current sub-classing issues as well aren't they). That is, if the implemented class adds a new property, your class will inherit the property as if you sub-classed.
On the down side, the caller is somewhat blind to the PEMs'. That is, by using the This_Access method, the PEMs' are only made available "just in time". Try using PEMSTATUS() or AMEMBERS() on the oMyProject object and see what is returned?
I will let you know how this design holds up in the VFP Solution Explorer project.
Powered By Qumana


Post a Comment

<< Home