当前位置: 代码迷 >> 综合 >> 【设计模式基础】行为模式 - 2 - 访问者(Visitor)
  详细解决方案

【设计模式基础】行为模式 - 2 - 访问者(Visitor)

热度:85   发布时间:2023-12-14 20:06:02.0

1. 模式意图

访问者模式的目的是封装一些施加于某种数据结构元素之上的操作;一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。

访问者模式使用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。

数据结构的每一个节点都可以接受一个访问者的调用,此节点向访问者传入节点对象,而访问者对象则反过来执行节点对象的操作。这样的过程叫做”双重分派“,节点调用访问者,将它自己传入,访问者则将某算法针对此节点执行。

双重分派意味着施加于节点之上的操作是基于访问者和节点本身的数据类型,而不是仅仅是其中的一者


访问者模式有如下的优点:

  • 访问者模式使得增加新的操作变得容易;如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,增加新的操作会很复杂;而使用访问者模式,增加新的操作就意味着增加一个新的访问者类
  • 访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中
  • 访问者模式可以阔过几个类的等级结构访问属于不同的等级结构的成员类
  • 积累状态,每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中执行操作的状态积累在自己内部,而不是分散到很多的节点对象

访问者模式有如下的缺点:

  • 增加新的节点变得困难;每增加一个新的节点都意味着要在抽象访问者中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作
  • 破坏封装;访问者模式要求访问者对象访问并调用每一个节点对象的操作,这隐含了一个对所有节点对象的要求:它必须暴露一些自己的操作和内部状态,不然,访问者的访问就变得没有意义。


2. 模式定义



抽象访问者(Visitor):                      声明了一个多者多个访问操作,形成所有的具体元素角色必须实现的接口;为该对象结构中ConcreteElement的每一个类声明一个Visit操作,该操作的名字和特征标识了发送Visit请求给该访问者的那个类,这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。

具体访问者(ConcreteVisitor):    实现抽象访问者所声明的接口

抽象节点(Element):                      声明一个Accept操作,它可以接受一个访问者对象作为一个参数

具体节点(ConcreteElement):    实现Accept操作

结构对象(ObjectStructure):       可以遍历结构中的所有元素;可以提供一个高层次的接口让访问者对象可以访问每一个元素;可以是设计成一个复合对象或者一个聚集,如List或者Set


具体访问者的数目与具体节点的数目没有任何关系。


3. 模式实现

3.1 C#中的访问者模式

// Visitor pattern -- Structural example  
using System;
using System.Collections;// "Visitor"
abstract class Visitor
{// Methodsabstract public void VisitConcreteElementA(ConcreteElementA concreteElementA );abstract public void VisitConcreteElementB(ConcreteElementB concreteElementB );
}// "ConcreteVisitor1"
class ConcreteVisitor1 : Visitor
{// Methodsoverride public void VisitConcreteElementA(ConcreteElementA concreteElementA ){Console.WriteLine( "{0} visited by {1}",concreteElementA, this );}override public void VisitConcreteElementB(ConcreteElementB concreteElementB ){Console.WriteLine( "{0} visited by {1}",concreteElementB, this );}
}// "ConcreteVisitor2"
class ConcreteVisitor2 : Visitor
{// Methodsoverride public void VisitConcreteElementA(ConcreteElementA concreteElementA ){Console.WriteLine( "{0} visited by {1}",concreteElementA, this );}override public void VisitConcreteElementB(ConcreteElementB concreteElementB ){Console.WriteLine( "{0} visited by {1}",concreteElementB, this );}
}// "Element"
abstract class Element
{// Methodsabstract public void Accept( Visitor visitor );
}// "ConcreteElementA"
class ConcreteElementA : Element
{// Methodsoverride public void Accept( Visitor visitor ){visitor.VisitConcreteElementA( this );}public void OperationA(){}
}// "ConcreteElementB"
class ConcreteElementB : Element
{// Methodsoverride public void Accept( Visitor visitor ){visitor.VisitConcreteElementB( this );}public void OperationB(){}
}// "ObjectStructure"
class ObjectStructure
{// Fieldsprivate ArrayList elements = new ArrayList();// Methodspublic void Attach( Element element ){elements.Add( element );}public void Detach( Element element ){elements.Remove( element );}public void Accept( Visitor visitor ){foreach( Element e in elements )e.Accept( visitor );}
}/// <summary>
/// Client test
/// </summary>
public class Client
{public static void Main( string[] args ){// Setup structureObjectStructure o = new ObjectStructure();o.Attach( new ConcreteElementA() );o.Attach( new ConcreteElementB() );// Create visitor objectsConcreteVisitor1 v1 = new ConcreteVisitor1();ConcreteVisitor2 v2 = new ConcreteVisitor2();// Structure accepting visitorso.Accept( v1 );o.Accept( v2 );}
}


4. 模式应用