zoukankan      html  css  js  c++  java
  • Class Hierarchies in LotusScript let’s loosen things up!

    Coming back to Object-Oriented programming in LotusScript after a lengthy spell programming in only JavaScript was a bit of a shock: LotusScript isso restricted!  Everything has to be declared and set up in rigid class hierarchies that can't be rejigged on the fly like you can in JavaScript (which has no real classes, of course).  And yet, with the judicious use of LotusScript's Variant type, it's possible to free yourself from some of these more obvious restrictions.


    Problem - Class Hierarchies

    One restriction that's always bugged me about LotusScript OO, is that the class libraries are a one-way door.  Class Library A can access the classes in Class Library B, or Class Library B can access teh classes in Class Library A.  But they can't both access each other's classes.  To do so would set up an infinite loop of Use statements, which the Domino Designer Compiler does not allow.

    Here's an example of this problem.  I set up two classes in two separate LotusScript class libraries:  The Class CarClass is in the CarClasses library and the Class RoadClass is in the RoadClasses library.  Here's the code for the two classes:

    ' in CarClasses LotusScript libary
    Public Class CarClass
                  Private m_Name As String
                  Private m_TopSpeedKMH As Integer
                  Private m_Weight As String

                  Sub new(n, k, w)
                                  Me.m_Name = n
                                  Me.m_TopSpeedKMH = k
                                  Me.m_Weight = w

                  End Sub

                  Public Property Get theName As String
                                  theName = Me.m_Name
                  End Property

                  Public Property Get topSpeedKMH As Integer
                                  topSpeedKMH = Me.m_TopSpeedKMH
                  End Property

                  Public Property Get Weight As String
                                  Weight = Me.m_Weight
                  End Property

    End Class



    ' in RoadClasses LotusScript library
    Public Class RoadClass
                  Private m_Name As String
                  Private m_Length As String
                  Private m_ChargeType As String

                  Sub new(n, l, c)
                                  Me.m_Name = n
                                  Me.m_Length = l
                                  Me.ChargeType = c

                  End Sub

                  Public Property Get theName As String
                                  theName = Me.m_Name
                  End Property

                  Public Property Get theLength As String
                                  theLength = Me.m_Length
                  End Property

                  Public Property Get chargeType As String
                                  ChargeType = Me.m_ChargeType
                  End Property

                  Public Property Set chargeType As String
                                  If chargeType <> "" Then
                                                  Me.m_ChargeType = "Freeway"
                                  Else
                                                  chargeType = chargeType
                                  End If
                  End Property

    End Class



    And here's a test agent that creates object of both classes.  Obviously, that code must (and does) include Use statements that name the two libraries.

    ' Options section
    Option Public
    Option Declare
    Use "RoadClasses"
    Use "CarClasses"


    Sub Initialize
                  Dim myCarObj As New CarClass("Honda Jazz", 120, 100)
                  Dim myRoadObj As New RoadClass("M4", 500, "Tollway")

                  Messagebox "objects defined!"

    End Sub




    And here's how the objects look in the LotusScript Debugger when I've run my test agent:




    So far, so easy.  Now I want to extend CarClass to include some info about the roads on which it can travel.  I do this by creating an array of RoadClass objects as a member of CarClass, remembering to add the line Use "RoadClasses" to the Options section of the CarClasses library, so that CarClass knows about RoadClass.

    ' In Options
    Use "RoadClasses"

    Public Class CarClass
                  Private m_Name As String
                  Private m_TopSpeedKMH As Integer
                  Private m_Weight As String
                  Private m_PermittedRoads() As RoadClass

                  Sub new(n, k, w)
                                  Me.m_Name = n
                                  Me.m_TopSpeedKMH = k
                                  Me.m_Weight = w
                                  Redim Me.m_PermittedRoads(0)
                  End Sub

                  Public Function addRoad(newRoad As RoadClass)
                                  Dim arraySize As Integer
                                  If Me.m_PermittedRoads(0) Is Nothing Then
                                                  Set Me.m_PermittedRoads(0) = newRoad
                                  Else
                                                  arraySize = Ubound(Me.m_PermittedRoads)
                                                  Redim Preserve Me.m_PermittedRoads(arraySize + 1)
                                                  Set Me.m_PermittedRoads(arraySize + 1) = newRoad

                                  End If
                  End Function

                  Public Property Get theName As String
                                  theName = Me.m_Name
                  End Property

                  Public Property Get topSpeedKMH As Integer
                                  topSpeedKMH = Me.m_TopSpeedKMH
                  End Property

                  Public Property Get Weight As String
                                  Weight = Me.m_Weight
                  End Property

    End Class



    I then modify the test agent to pass some RoadClass objects into my CarClass object.  Here's how the code and its results look in the Domino Debugger:



    You can see how the m_PermittedRoads property of the myCarObj contains an array of RoadClass objects, as we intended.  But what happens if we also want to do the reverse of this; i.e. I want my RoadClass object to have an array of CarClass objects, which are the types of car that are permitted to drive on my road?

    Here's how I might try to set that up in CarClass class.  You can see that I've added a Use statement to pull in the CarClasses library.  I've then setup a class variable that is an array of CarClass objects.

    ' In Options
    Use "CarClasses"

    Public Class RoadClass
                  Private m_Name As String
                  Private m_Length As String
                  Private m_ChargeType As String
                  Private m_CarTypes() As CarClass
                 ....


    And here is where it all falls down.  The Domino Designer won't save this code; it will throw the error "RoadClasses (Options): 3: Error loading USE or USELSX module: CarClasses".

    Why won't it load the "CarClasses"?  It's because the "CarClasses" library is already loading the "RoadClasses" library via its Use statement.  And as I said earlier, two LotusScript libraries cannot "load" each other.  That would put us you an infinite loop where CarClasses uses RoadClasses, which uses CarClasses, which uses RoadClasses .... and round, and round we go. Not suprising then that the Designer throws a wobbler.


    Solution

    One possible solution is to put both classes in the same library, but this leads to an inflexibility that might end up causing more problems than it solves.

    My answer is to instantiate my class objects as type Variant, rather than as their actual class-types.  The Designer does not do compile-time type checking for Variants, so we don't then need to have each library contain a Use statement that tries to load up the other.  Only the calling code - our test agent in this case - needs to load up the two libraries.  This allows us to eat our cake and still have it.

    The code below shows the changes: the m_PermittedRoads class variable and the newRoad parameter of the addRoad function are both now defined as Variants.  This means that we no longer have to include a Use "RoadClasses" line in the Options section of the library; we merely need have both libraries loaded in the calling agent, as we did previously.  The RoadClass objects are declared and instantiated in the calling test agent, and then passed into CarClass's addRoad method as a Variant.

    I've also added a PermittedRoads Get Property so that we can access the variable later on and test what it is and what it can do.  Here's the modified CarClass library.  Note that the problematic Use "RoadClass" line is gone as we no longer need it.

    Public Class CarClass
                  Private m_Name As String
                  Private m_TopSpeedKMH As Integer
                  Private m_Weight As String
                  Private m_PermittedRoads() As Variant

                  Sub new(n, k, w)
                                  Me.m_Name = n
                                  Me.m_TopSpeedKMH = k
                                  Me.m_Weight = w
                                  Redim Me.m_PermittedRoads(0)
                  End Sub

                  Public Function addRoad(newRoad As Variant)
                                  Dim arraySize As Integer
                                  If Me.m_PermittedRoads(0) Is Nothing Then
                                                  Set Me.m_PermittedRoads(0) = newRoad
                                  Else
                                                  arraySize = Ubound(Me.m_PermittedRoads
    )
                                                  Redim Preserve Me.m_PermittedRoads(
    arraySize + 1)
                                                  Set Me.m_PermittedRoads(arraySize + 1)
    = newRoad
                                  End If
                  End Function

                  Public Property Get theName As String
                                  theName = Me.m_Name
                  End Property

                  Public Property Get topSpeedKMH As Integer
                                  topSpeedKMH = Me.m_TopSpeedKMH
                  End Property

                  Public Property Get Weight As String
                                  Weight = Me.m_Weight
                  End Property

                 Public Property Get PermittedRoads As Variant
                                  PermittedRoads = Me.m_PermittedRoads
                 End Property

    End Class



    Here's the modified calling agent as it appears on the LotusScript Debugger. I've called the new PermittedRoads property of myCarObj tor return the first of the RoadClass objects that I passed into it on the agent's two previous lines.  Although this object is returned as type Variant (as displayed in the Degugger), I can still access it's theName property, which proves that it's really a RoadClass object.




  • 相关阅读:
    让你忘记 Flash 的15款精彩 HTML5 游戏
    经典网页设计:10个响应式设计的国外购物网站
    个人网站设计:25个国外优秀案例带给你灵感
    震撼!20幅令人难以置信的摄影图片欣赏
    Vex – 超轻量!可以轻松自定义的现代风格弹窗插件
    高端大气上档次!10个精美的国外HTML5网站欣赏
    桂系军阀老大为何不是打仗独步天下的白崇禧?三个方面不如李宗仁(气量,人缘,大局观)
    LEO原创-FMX之你不知道的ARC
    ubuntu64位系统编译时头文件找不到的问题(可以查看g++ -v路径,设置export C_INCLUDE_PATH,CPLUS_INCLUDE_PATH)
    qt设计器中使用自定义控件
  • 原文地址:https://www.cnblogs.com/hannover/p/2466105.html
Copyright © 2011-2022 走看看