Design Patterns(二十四):Visite Pattern--VB代码

结构图

 

角色

  • 抽象访问者(Visitor)角色:声明了一个或多个访问操作,形成所有的具体元素角色必须的接口。
  • 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口,也就是抽象访问者所声明的各个访问操作。 
  • 元素(Element)角色:定义一个接受操作,它以一个访问者为参数。 
  • 具体元素(ConcreteElement)角色:实现一个接受操作,它以一个访问者为参数。 
  • 对象结构(ObjectStructure)角色:可以提供一个高层接口以允许该访问者访问它的元素;可以是一个复合对象或集合对象。 

动机

  在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给予类带来很繁重的变更负担,甚至破坏原有设计。。
   如何在不更改类层次结构的前提下,在运行时根据需要透明地为类层次结构萨哈那个的各个类动态添加新的操作,从而避免上述问题?

意图
   表示一个作用于某对象结构中的各元素的操作。它可以在不改变各元素的类的前提下定义作用于这些元素的新的操作。

示意性代码

结构代码
'Visitor pattern -- Structural example

Imports System
Imports System.Collection

'MainApp test application 
Module MainApp
    
Public Sub Main
        
'Setup structure
        Dim o as new objectstructure
        o.Attach(
new ConcreteElementA)
        o.Attach(
new ConcreteElementB)
        
        
'Create visitor objects
        Dim v1 as new concreteVisitor1
        
dim v2 as new concretevisitor2
        
        
'Structure accepting visitors
        o.Accept(v1)
        o.Accept(v2)
        
        
'Wait for user
        Console.ReadLine()
    
End Sub
End Module

'"Visitor"
public mustinherit class Visitor
    
public mustoverride sub VisitConcreteElementA( _
        
byval concreteElementA as concreteElementA) 
    
public mustoverride sub VisitConcreteElementB( _
        
byval concreteElementB as concreteElementB)
end class

'"ConcreteVisitor1"
public class ConcreteVisitor1
    
inherits Visitor
    
public overrides sub VisitConcreteElementA( _
        
byval concreteElementA as concreteElementA) 
        Console.WriteLine(
"{0} visited by {1}", _
            concreteElementA.GetType().Name,
me.GetType().Name)
    
end sub
    
public overrides sub VisitConcreteElementB( _
        
byval concreteElementB as concreteElementB)
        Console.WriteLine(
"{0} visited by {1}", _
            concreteElementB.GetType().Name,
me.GetType().Name)
    
end sub
end class

'"ConcreteVisitor2"
public class ConcreteVisitor2
    
inherits Visitor
    
public overrides sub VisitConcreteElementA( _
        
byval concreteElementA as concreteElementA) 
        Console.WriteLine(
"{0} visited by {1}", _
            concreteElementA.GetType().Name,
me.GetType().Name)
    
end sub
    
public overrides sub VisitConcreteElementB( _
        
byval concreteElementB as concreteElementB)
        Console.WriteLine(
"{0} visited by {1}", _
            concreteElementB.GetType().Name,
me.GetType().Name)
    
end sub
end class

'"Element"
public mustinherit class Element
    
public mustoverride sub Accept(byval visitor as Visitor)
end class

'"ConcreteElementA"
public class ConcreteElementA
    
inherits Element
    
public overrides sub Accept(byval visitor as Visitor)
        visitor.VisitConcreteElementA(
me)
    
End sub
    
public sub OperationB()
    
End sub
end class

'"ConcreteElementB"
public class ConcreteElementB
    
inherits Element
    
public overrides sub Accept(byval visitor as Visitor)
        visitor.VisitConcreteElementB(
me)
    
End sub
    
public sub OperationB()
    
End sub
end class

'"ObjectStructure"
public class ObjectStructure
    
private elements as new ArrayList
    
public sub Attach(byval element as Element)
        elements.Add(element)
    
end sub
    
public sub Detach(byval element as Element)
        elements.remove(element)
    
end sub
    
public sub Accept(byval visitor as Visitor)
        
for each e as element in elements
            e.Accept(visitor)
        
next
    
end sub
End Class

一个实例

以下的例子演示了Employee对象集合允许被不同的Visitor(IncomeVisitor与VacationVisitor)访问其中的内容。

实例代码
' Visitor pattern -- Real World example

Imports System
Imports System.Collections

' MainApp startup application
Module MainApp
    
Private Shared Sub Main()
        
' Setup employee collection
        Dim e As New Employees()
        e.Attach(
New Clerk())
        e.Attach(
New Director())
        e.Attach(
New President())
       
        
' Employees are 'visited'
        e.Accept(New IncomeVisitor())
        e.Accept(
New VacationVisitor())
       
        
' Wait for user
        Console.Read()
    
End Sub
End Module

'"Visitor"
Public Interface IVisitor
    
Sub Visit(ByVal element As Element)
End Interface

'"ConcreteVisitor1"
Public Class IncomeVisitor
    
Implements IVisitor
    
Public Sub Visit(ByVal element As Element) Implements IVisitor.Visit
        
Dim employee As Employee = TryCast(element, Employee)
       
        
' Provide 10% pay raise
        employee.Income *= 1.1
        Console.WriteLine(
"{0} {1}'s new income: {2:C}", employee.[GetType]().Name, employee.Name, employee.Income)
    
End Sub
End Class

'"ConcreteVisitor2"
Public Class VacationVisitor
    
Implements IVisitor
    
Public Sub Visit(ByVal element As Element) Implements IVisitor.Visit
        
Dim employee As Employee = TryCast(element, Employee)
       
        
' Provide 3 extra vacation days
        Console.WriteLine("{0} {1}'s new vacation days: {2}", employee.[GetType]().Name, employee.Name, employee.VacationDays)
    
End Sub
End Class

Public Class Clerk
    
Inherits Employee
    
' Constructor
    Public Sub New()
        
MyBase.New("Hank"2500014)
    
End Sub
End Class

Public Class Director
    
Inherits Employee
    
' Constructor
    Public Sub New()
        
MyBase.New("Elly"3500016)
    
End Sub
End Class

Public Class President
    
Inherits Employee
    
' Constructor
    Public Sub New()
        
MyBase.New("Dick"4500021)
    
End Sub
End Class

'"Element"
Public MustInherit Class Element
    
Public MustOverride Sub Accept(ByVal visitor As IVisitor)
End Class

'"ConcreteElement"
Public Class Employee
    
Inherits Element
    
Private m_name As String
    
Private m_income As Double
    
Private m_vacationDays As Integer
   
    
' Constructor
    Public Sub New(ByVal name As StringByVal income As DoubleByVal vacationDays As Integer)
        
Me.m_name = name
        
Me.m_income = income
        
Me.m_vacationDays = vacationDays
    
End Sub
   
    
' Properties
    Public Property Name() As String
        
Get
            
Return m_name
        
End Get
        
Set
            m_name 
= value
        
End Set
    
End Property
   
    
Public Property Income() As Double
        
Get
            
Return m_income
        
End Get
        
Set
            m_income 
= value
        
End Set
    
End Property
   
    
Public Property VacationDays() As Integer
        
Get
            
Return m_vacationDays
        
End Get
        
Set
            m_vacationDays 
= value
        
End Set
    
End Property
   
    
Public Overloads Overrides Sub Accept(ByVal visitor As IVisitor)
        visitor.Visit(
Me)
    
End Sub
End Class

'"ObjectStructure"
Public Class Employees
    
Private employees As New ArrayList()
   
    
Public Sub Attach(ByVal employee As Employee)
        employees.Add(employee)
    
End Sub
   
    
Public Sub Detach(ByVal employee As Employee)
        employees.Remove(employee)
    
End Sub
   
    
Public Sub Accept(ByVal visitor As IVisitor)
        
For Each e As Employee In employees
            e.Accept(visitor)
        
Next
        Console.WriteLine()
    
End Sub
End Class

Visitor Pattern模式的几个要点:
   1、Visitor模式通过所谓双重分发(double dispatch)来实现在不更改Element类层次结构的前提下,在运行时透明地为类层次结构上的各个类动态添加新的操作。
   2、所谓双重分发即Visitor模式中间包括了两个多态分发(注意其中的多态机制):第一个为accept方法的多态辨析;第二个为visit方法的多态辨析。
   3、Visitor模式的最大缺点在于扩展类层次结构(增添新的Element子类),会导致Visitor类的改变。因此Visitor模式适用于“Element类层次结构稳定,而其中的操作却经常面临频繁改动”。

我的理解

封装对象操作变化,支持在运行时为类层次结构动态添加新的操作。

参考资料
《C#面向对象设计模式纵横谈系列课程(24)》     李建中老师

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值