Interfaces & Abstract Classes with LotusScript
Interface and abstract classes define objects properties and methods, just as ordinary classes do. One generally creates as many objects as necessary from standard classes, while interface classes are solely intended to describe contracts that future objects will guarantee. Interfaces classes usually contain no code and can't be used to instantiate objects. In turn abstract classes prototype properties and methods. Abstract classes can't be instantiated either and require to be derived so that its subclasses benefit from their code. Compilers closely control interface compliant classes and usually prevent from interface or abstract classes instantiations.
Designers usually resort to interface or abstract classes to build loosely coupled application code that's more adaptable, more maintainable and ends up being more robust. Although such class constructs are missing from native LotusScript, those object oriented design concepts can be implemented in your LotusScript code with little effort.
As an exemple, consider designing a LotusScript.io.File class that holds the following subset of attributes and operations: canWrite( ), getAbsolutePath( ), length( ), list( ), renameTo( ). You may either develop a full LotusScript solution, either build an LS2J based solution, either resort to Windows Script Host COM object library or even call Windows/32 native functions. Defining iFile interface class sounds a valuable approach that exhibits properties and methods regardless of the implemented inner workings. While your calling code relies on a stable interface, your concrete implementations can vary at will or be changed without notice. Doing so you're building a loosely coupled Notes or Domino application.
Figure 1: StopWatches UML Class Diagram
OpenDOM open source project you can download from www.openntf.org contains numerous code samples benefitting from interfaces and abstract classes design constructs. Its LotusScript.lang.StopWatches library uses iTicker public interface in four different implementations accommodating LotusScript release 3 and 4+, Windows/16 and Windows/32 contexts. LotusScript.lang.Rn or LotusScript.windows.winnn packages, or namespaces, contain iTicker interface compliant concrete classes. StopWatches public class internal iTicker engine gets loaded dynamically according to the most appropriate situation.
You can prevent from objects instantiation, and make sure properties and methods get derived or overridden. But creating private LotusScript class constructors as in ..
<noteName>: <eventName>: <lineNumber>: Illegal PRIVATE declaration of: NEW
As LotusScript does not natively support interface classes or private constructors as above I adopted another approach. I prevent from interface or abstracts classes instantiation at runtime only throwing exception in class constructors, I force properties and methods to be derived throwing equivalent runtime exceptions as in :
Once I established my interface, I can devise to write as many concrete classes implementing it and provide a factory class or routine serving context dependent objects :
OpenDOM LotusScript.lang.Factory class creates objects this way. It is inspired from « Performance Considerations for Domino Applications » IBM redbook whose « B-2 Dynamic Script Library Loading » worth reading appendix explains how to dynamically load LotusScript libraries in your object oriented programs. While IBM code performs objects dynamic instantiation, attentive reading reveals such is accomplished using variants that defeat compiler time type checks. Adding interface classes your code overcomes this obstacle and offers multiple advantages :
Places of interest:
OpenDOM open source project you can download from www.openntf.org contains numerous code samples benefitting from interfaces and abstract classes design constructs. Its LotusScript.lang.StopWatches library uses iTicker public interface in four different implementations accommodating LotusScript release 3 and 4+, Windows/16 and Windows/32 contexts. LotusScript.lang.Rn or LotusScript.windows.winnn packages, or namespaces, contain iTicker interface compliant concrete classes. StopWatches public class internal iTicker engine gets loaded dynamically according to the most appropriate situation.
You can prevent from objects instantiation, and make sure properties and methods get derived or overridden. But creating private LotusScript class constructors as in ..
.. throws the following compiler exception :Public Class iVehicle
Private Sub New
End Sub
End Class ' iVehicle
<noteName>: <eventName>: <lineNumber>: Illegal PRIVATE declaration of: NEW
As LotusScript does not natively support interface classes or private constructors as above I adopted another approach. I prevent from interface or abstracts classes instantiation at runtime only throwing exception in class constructors, I force properties and methods to be derived throwing equivalent runtime exceptions as in :
%INCLUDE "LsErr.lss"
Public Class iVehicle '
Public Sub New ' This forbids interface instantiation, please derive me !
If Typename( Me ) = "IVEHICLE" Then Error ErrNotAnObject
End Sub ' New
Public Property Get Color As NotesColor
Error errPropGetNotDefined
End Property ' Color
Public Property Set Price As Currency
Error errPropSetNotDefined
End Property ' Price
Public Sub starts( )
Error ErrNotAMethod
End Sub ' starts( )
End Class ' iVehicle
Public Class aShuttle
Public Property Get isFree As Boolean '
Error errPropSetNotDefined
End Property ' isFree
End Class ' aShuttle
Once I established my interface, I can devise to write as many concrete classes implementing it and provide a factory class or routine serving context dependent objects :
Private Class Car As iVehicle
' Your code goes here ..
End Class ' Car As iVehicle
Private Class Truck As iVehicle
' Your code goes here ..
End Class ' Truck As iVehicle
Public Function createVehicle As iVehicle
If ( so And so ) Then
Set Me.createVehicle = New Car
Else
Set Me.createVehicle = New Truck
End If
End Function
OpenDOM LotusScript.lang.Factory class creates objects this way. It is inspired from « Performance Considerations for Domino Applications » IBM redbook whose « B-2 Dynamic Script Library Loading » worth reading appendix explains how to dynamically load LotusScript libraries in your object oriented programs. While IBM code performs objects dynamic instantiation, attentive reading reveals such is accomplished using variants that defeat compiler time type checks. Adding interface classes your code overcomes this obstacle and offers multiple advantages :
- You're designing loosely coupled LotusScript while building application classes regardless of their internal technical alternatives you will freely accommodate,
- Early bound objects allow type safety controls to occur at compile time which is considered a best practice,
- LotusScript interpreter memory footprint increases progressively as library objects are gradually loaded. Although libraries are compiled prior to be loaded, this gets mostly unnoticed and is largely compensated by memory minimised consumption.
Places of interest:
- « Lotus Notes and Object-Oriented System Design », Mikko Valjakka
- Appendix « B-2 Dynamic Script Library Loading » in Performance Considerations for Domino Applications IBM RedBook
«Dynamic loading of LotusScript libraries» in HADSL blog - « Leveraging the Power of Object Oriented Programming in LotusScript », Jens-B Augustiny & Wild Bill Buchan
« Object Orientated Programming in LotusScript », Wild Bill Buchan - « Objektorientierung in LotusScript effizient einsetzen », Bernd Hort
Labels: abstract class, interface class, LotusScript, Object Oriented Design, Object Oriented Programming, OOD, OOP, SnTT