« How cool is this? | Main| Two year anniversary »

06/22/2007

Dynamic Loading Script Libraries, Late Binding and a Flexible Parameter

Category   

Beginning on page 243 of the greatly revered 'Performance Considerations for Domino Applications' there is a discussion of the concept of dynamically loading Lotusscript libraries that contain individual object oriented custom classes.  I LOVE this technique.  I have an application that has close to 150 classes and loading them all at once is a huge performance drain; this technique alleviates that problem.

But it does introduce a different problem.

On page 246, there is a note:

Note We did not need to pass parameters to the class constructor in our
application. However, we could have allowed parameters to be passed
into NewObj, which in turn would be passed into the constructor if
necessary. This would impose the restriction that the constructors of all
classes to be used with NewObj would need to accept the same
parameter.

To this I say 'Bollocks'!  I really need to pass parameters to my classes...different parameters all the time...sometimes a string, sometimes a date, often an Notes object like a NotesUIDocument.  Sometimes I even need to pass a whole slew of parameters to the class.

The code presented by the Redbook looks like this:
(error checking/handling removed from all code for brevity)

Function NewObj( className As String ) As Variant
        If Not IsElement( factories( className ) ) Then
                Dim script As String
                script = |
                Use "| & className & |"
                        Sub Initialize
                                Set newObj_factory = New | & className & |Factory
                        End Sub
                |
                Execute (script)
                Set factories( className ) = newObj_factory
        End If
       
        Set NewObj = factories( className ).produce

End Function

Which is called like this:

Set obj = NewObj( "MyClass" )


My loader looks like this:

Function newObj(strClassName As String, parameter As Variant) As Variant
        If Not Iselement(fact_objs(strClassName)) Then
                Dim strLibName As String
                strLibName = "class:" & strClassName
                Dim strExec As String
                strExec = |
       Use "| & strLibName & |"
       sub Initialize
       set newObj_Factory = new | & strClassName & |Factory
       End sub
       |
                Execute(strExec)
                Set fact_objs(strClassName) = newObj_Factory
        End If
        Set newObj = fact_objs(strClassName).produce(parameter)
End Function


Which is called like this: (in this case I am passing a NotesUIDocument object as a parameter from a form's queryopen event)

Sub Queryopen(Source As Notesuidocument, Mode As Integer, Isnewdoc As Variant, Continue As Variant)
       
        On Error Goto ERROR_HANDLER
        Set oDoc = newObj("Organization", Source)
        Exit Sub
       
ERROR_HANDLER:
        Call ErrorHandler.HandleError(MODULE_NAME, "", Null)
        Exit Sub
       
End Sub


My factory class (which is what is used to instanciate the object, defined in the script library,) looks like this:

Public Class OrganizationFactory
        Function produce(Source As NotesUIDocument) As Variant
                Set produce = New Organization(Source)
        End Function
End Class


And finally, the class itself (BaseForm is an 'intermediary' class that all of my form classes are derived from, it contains standard form processing code):

Private Class Organization As BaseForm
       
        Sub New (Source As NotesUIDocument)
                On Event PostOpen From Source Call EventPostOpen
                On Event QueryModeChange From Source Call EventQueryModeChange
                On Event PostModeChange From Source Call EventPostModeChange
                On Event QuerySave From Source Call EventQuerySave
                On Event PostSave From Source Call EventPostSave
        End Sub

<snip>
bunch of event handling code
</snip>

End Class


This class is used to control the explicit processing I do against this particular form and it may or may not override the processing coded in the BaseForm class

All of my custom class script libraries follow a simple naming convention "class:" and then the class name, so for the code above my 'Organization' class resides in a library named 'class:Organization'.

What is cool about this loader/factory/class technique is that you get the benefits of dynamic loading, plus the ability to pass a parameter AND since you are passing around a reference to a Variant, the parameter can be anything known to the class (any native datatype, an object, a custom datatype (I use these for mutliple parameters.) All that matters is that the class define the required parameter either explicitly (for improved error checking) or expect a variant itself.

If you don't need a parameter, you still need to setup a 'dummy' parameter to statisfy the compiler, but you simply pass a null or nothing value and don't have your class do anything with the parameter.

Comments

Gravatar Image1 - That's gonna take me a bit to digest. It looks pretty cool, though, and thanks very much for sharing. Emoticon

Gravatar Image2 - That's a great compromise! Thanks for sharing.

Gravatar Image3 - I tend to follow a different path allowing me to overcome LotusScript unique constructor limitation while still benefitting from dynamic class loading:

' I grab an (optional) default class object and get specific objects (with/out parms) this way..
Set myClass=NewObj( "pkg.Circle")
parameters) this way..
Set c1 = obj.getCircle1(point)
Set c2 = obj.getCircle2(radius, point)

' or resort to static class methods to build specific objects..
Set c1 = pkg.Circle.getCircle1(point)
Set c2 = pkg.Circle.getCircle2(radius, point)

I am convinced DOM objects should not be passed as parameters BUT «problem domain» objects instead, DOM objects are wrapped within objects encapsulating back-end and front-end abilities in class constructors:

Class Person
Private be As NotesSession
Public Sub New
Set be = New NotesSession
End Sub
End Class ' Person

Class UIPerson As Person
Private ui As NotesUIWorkSpace
Public Sub New
Set ui = New NotesUIWorkspace
End Sub
End Class ' UIPerson

thus registering to an event is a combination of intermingled UI and persistence routines initiated from agents, buttons, forms, views, etc..

aPerson.subscribes( aEvent )
thisPerson.subscribes( thisEvent )

Cordially

Gravatar Image4 - scf

Gravatar Image5 - i have design a site there is flash element also and it take too much time to load. i want when i enter the index page it should start load other pages in backend can you help me to do this

Post A Comment

:-D:-o:-p:-x:-(:-):-\:angry::cool::cry::emb::grin::huh::laugh::lips::rolleyes:;-)

misc links

search my blog

domino blogger search

coComments

tag cloud