%REM This is an example of how to write a pseudo-Singleton class in LotusScript. It's not as straightforward as creating a classic Singleton class in a fully object-oriented language because: 1. LotusScript classes can't have static methods 2. LotusScript classes can't have Private constructors One way people try to create Singletons is by creating a global instance of some Public class, writing a "factory" function that returns the global instance (instantiating it if necessary), and then hoping that anything that calls your code uses the factory function instead of just creating a new instance of your class on its own. What you're really doing there is creating a global instance of the class object though, not a true single instance. If someone decides to skip your factory function and create their own instance of your class, suddenly you have two instances of the class running around, acting independently. Here's a trick to get around that. If you declare a class as PRIVATE in a script library, it's not accessible outside the library. However, if you have something inside that script library (class method or function) that returns an instance of that Private class as a VARIANT, then suddenly you can call all the methods of that PRIVATE class and use it just like it's a regular Public class. Since LotusScript doesn't have any kind of type-ahead for custom classes, you don't lose any functionality -- you still have to refer back to the original class to see how it works anyway. And it solves the problem of having to cross your fingers and hope that developers who call your class call it the way you tell them to (i.e. -- using a factory, or only ever referring to a single global instance). Instead, a developer HAS to use your factory to get an instance of your class, but they can use it just like any other class -- the only difference being that changes to one instance of the class will affect all instances of the class. Another nice thing about this implementation is that it's very easy to take an existing class and make it Singleton-like. Just turn it into a Private class, create a Private global instance of it, and write the small Public factory class. An example implementation of this type of pseudo-Singleton class is provided below. If you want to test it, save it all in the Declarations section of a script library and write an agent like this: ================================ Option Public Option Declare '** obviously, use the name of your script library here Use "ThingTest" Sub Initialize Dim MyMessageThing As Variant Dim MyOtherMessageThing As Variant Dim factory As New ThingFactory '** get your MessageThings Set MyMessageThing = factory.getMessageThing() Set MyOtherMessageThing = factory.getMessageThing() '** both things act like the same object, because '** a modification to one also modifies the other. Print "Message = " & MyMessageThing.getMessage MyOtherMessageThing.setMessage("blah") Print "Message = " & MyMessageThing.getMessage Print "Are these things the same? " & _ (MyMessageThing Is MyOtherMessageThing) '** can't do this, because singleMessage is Private 'Print singleMessage.getMessage '** can't do this either, because MessageThing '** is also Private 'Dim mt3 As New MessageThing End Sub ================================ As with much of the other code that I write and publish, you can use this code in any way you want, as long as you don't hold me liable for anything, and you don't pretend you wrote it yourself (i.e. -- please give proper attribution). Thanks VERY MUCH to Bill Buchan ( http://www.billbuchan.com ) for looking at my initial implementation of all this and pointing out that I could use the factory method instead of the wrapper method I had originally devised. version 1.0 December 26, 2005 Julian Robichaux ( http://www.nsftools.com ) %END REM '** This is the class we use as the basis of our pseudo-Singleton '** class. Because it's Private, nothing outside of this script library '** can create an instance of it. However, all the public methods '** will be available when the class is obtained from the factory. Private Class MessageThing Public msg As String Public Sub setMessage (msg As String) Me.msg = msg End Sub Public Function getMessage() As String getMessage = msg End Function End Class '** This is the single instance of MessageThing we'll be referencing. '** Its methods can be called by other classes in this script '** library, but because it's Private, other code that uses this '** library can't access it directly -- it can only be used by other '** classes and functions in this library (and we're making sure '** that this library's code uses it responsibly) Private singleMessage As MessageThing '** Finally, this is the class that acts as our pseudo-Singleton '** class. It instantiates the singleMessage variable above if '** necessary, and returns a pointer to it as a Variant. '** '** Note that you can actually have multiple instances of this factory '** class, but each instance is really referring back to a single '** instance of the Private class, which is the real point. And luckily '** for us, LotusScript doesn't have threads so we don't have to '** code around any weird multi-threading possibilities. '** '** The entire factory class below could also just be a function, if you '** wanted to write it that way. Public Class ThingFactory Public Function getMessageThing() As Variant If (singleMessage Is Nothing) Then Set singleMessage = New MessageThing End If Set getMessageThing = singleMessage End Function End Class
This LotusScript was converted to HTML using the ls2html routine,
provided by Julian Robichaux at nsftools.com.