IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]98. 面向对象的LotusScript(十七)之LinkedCollection

    starrow发表于 2015-03-24 14:54:45
    love 0

    面向对象编程经常会用到作为容器的对象,使用LotusScript时因为基本上是和单一的数据对象NotesDocument打交道,用作容器的就是数据库的视图或包含搜索结果的文档集合。但有时也需要某个通用容器来容纳其他自定义的对象。此时一般可考虑用数组,或者像20. 面向对象的LotusScript(三)之NArray介绍的编写一个基于动态数组的容器类。本文给出另一种容器的实现方式,对外的接口也像NArray一样是一个Collection,内部实现则不依赖于数组,而采用链接的节点。由于LotusScript的数组在包含数组时有层次上的限制,所以本容器类在理论上适用范围更广(虽然极少遇到这样极端的情况,基本上还是作为一个普通的容器类使用)。

    '先定义一个用作节点的类
    Class LinkedNode
        Public PreviousNode As LinkedNode
        Public NextNode As LinkedNode
        Public Value As Variant
    
        'prevNode As LinkedNode, nextNode As LinkedNode
        Sub New(value As Variant)
            Call SetValue(me.Value, value)
        End Sub 
    
        Sub Append(nnode As LinkedNode)
            Set me.NextNode=nnode
            Set nnode.PreviousNode=Me
        End Sub 
    
        Function IsEqualTo(node As LinkedNode) As Boolean
            If node Is Me Then
                IsEqualTo=True
                Exit Function 
            End If
    
            If Equals(node.Value, me.Value) Then
                IsEqualTo=True
            Else
                IsEqualTo=False             
            End If
        End Function
    End Class
    '接下来是链接集合类
    Class LinkedCollection
        Private msize As Integer
        Private anchor As LinkedNode
        Private current As LinkedNode
        'Public Parent As LinkedCollection
    
        Sub New()
            Set anchor=New LinkedNode(Null)
            Call anchor.Append(anchor)
            Call Me.Reset()
            'Set anchor.PreviousNode=anchor
            'Set anchor.NextNode=anchor
        End Sub
    
        Property Get Size As Integer
            Size=msize
        End Property
    
        Function FirstNode() As LinkedNode
            Dim node As LinkedNode
            Set node=anchor.NextNode
            If Not anchor.NextNode Is anchor Then
                Set FirstNode=anchor.NextNode
            End If
        End Function
    
        Function LastNode() As LinkedNode
            If Not anchor.PreviousNode Is anchor Then
                Set LastNode = anchor.PreviousNode
            End If 
        End Function
    
        Sub Reset()
            Set current=anchor
        End Sub
    
        Function HasNext() As Boolean
            HasNext=Not current.NextNode Is anchor
        End Function
    
        Function Next() As LinkedNode
            Set current=current.NextNode
            If current Is anchor Then
                Set Me.Next=Nothing 
                'Error 4000, "LinkedList: no such element."
            End If
            Set Me.Next=current
        End Function 
    
        Function Add(value As Variant)
            Dim node As New LinkedNode(value)
            Call anchor.PreviousNode.Append(node)
            Call node.Append(anchor)
            msize=msize+1
        End Function
    
        Function Contains(value As Variant) As Boolean
            If Find(value) Is Nothing Then
                Contains=False
            Else
                Contains=True 
            End If
        End Function
    
        Function ContainsNode(node As LinkedNode) As Boolean
            Call Me.Reset()
            While HasNext()
                If Me.Next() Is node Then
                    ContainsNode=True   
                End If
            Wend        
            ContainsNode=False 
        End Function
    
        Function Remove(value As Variant) As Boolean
            Dim node As LinkedNode
            Set node=Find(value)
            If node Is Nothing Then
                Me.Remove=False 
            Else
                Call DirectRemoveNode(node)
                Me.Remove=True 
            End If      
        End Function
    
        Function RemoveCurrent() As Boolean
            If current Is anchor Then
                RemoveCurrent=False
            Else
                Call DirectRemoveNode(current)
                Set current=current.PreviousNode
            End If
        End Function
    
        Private Sub DirectRemoveNode(node As LinkedNode)
            Call node.PreviousNode.Append(node.NextNode)
            msize=msize-1       
        End Sub
    
        Function Find(value As Variant) As LinkedNode
            Dim node As LinkedNode 
            Call Me.Reset()
            While HasNext()
                Set node=Me.Next()
                If Equals(value, node.Value) Then
                    Set Find=node
                    Exit Function 
                End If
            Wend        
        End Function
    
        Function Clone() As LinkedCollection
            Dim col As New LinkedCollection
            'Dim node As LinkedNode
            Call Me.Reset()
            While HasNext()
                Call col.Add(Me.Next().Value)   
            Wend
            'Set col.Parent=me.Parent
            Set Clone=col
        End Function
    
        Function AddArray(array As Variant)
            ForAll e In array
                Add(e)
            End ForAll
        End Function
    
        'The node value of two LinkedCollection instances must not point to their 
        'ancestors of LinkedCollection in the same hierarchy level. Or an infinite loop
        'will occur during comparing these two instances.   
        Function IsEqualTo(lc As Variant) As Boolean
            If Not InstanceOf(lc, TypeName(Me)) Then
                IsEqualTo=False
                Exit Function           
            End If
    
            If lc Is Me Then
                IsEqualTo=True
                Exit Function           
            End If
    
            If lc.Size >< me.Size Then
                IsEqualTo=False
                Exit Function           
            End If
    
            Dim c1 As LinkedCollection, c2 As LinkedCollection      
            Set c1=Me.Clone()
            Set c2=lc.Clone()
            Call c1.Reset()
            Call c2.Reset()
            While c1.HasNext()
                If c2.Remove(c1.Next().Value) Then
                    Call c1.RemoveCurrent()             
                Else
                    IsEqualTo=False
                    Exit Function 
                End If
            Wend
            IsEqualTo=True 
        End Function
    End Class

    该集合类的方法从名称上都可以看出含义,包括添加单个值、添加数组、克隆、判断是否包含某值、查找包含某值的节点、返回首个节点、判断是否还有下个节点、用于比较等值的IsEqualTo、返回末个节点、返回下个节点、删除包含某值的节点、删除当前节点、重置内部指针以及返回集合包含节点的数量。
    其中Reset、HasNext和Next三个方法合起来用于遍历集合内所有的节点:

    Call col.Reset()
    If col.HasNext() Then
        Set node=col.Next()
        value=node.Value '或Set value=node.Value
    End If

    注意LinkedCollection和LinkedNode类都有一个IsEqualTo方法,可以被87. 再谈变体型Variant里介绍的计算相等性的Equals函数调用。
    另外在LinkedCollection的链接实现方式上,采用了一个特殊的初始节点作为“锚”,使得对于从零到任意多个节点,在返回首位节点、添加节点、判断是否有下个节点等操作时,都有一致简单的逻辑。



沪ICP备19023445号-2号
友情链接