一、访问者模式介绍
1.1 访问者模式的定义
表示一个作用于某对象结构中的各个元素的操作。它使你可以在不改变各个元素的类的前提下定义作用于这些元素的新操作。
1.2 访问者模式的结构图
具体的访问者模式结构图如下所示。
这里需要明确一点:访问者模式中具体访问者的数目和具体节点的数目没有任何关系。从访问者的结构图可以看出,访问者模式涉及以下几类角色。
- 抽象访问者角色(Vistor):声明一个活多个访问操作,使得所有具体访问者必须实现的接口。
- 具体访问者角色(ConcreteVistor):实现抽象访问者角色中所有声明的接口。
- 抽象节点角色(Element):声明一个接受操作,接受一个访问者对象作为参数。
- 具体节点角色(ConcreteElement):实现抽象元素所规定的接受操作。
- 结构对象角色(ObjectStructure):节点的容器,可以包含多个不同类或接口的容器。
2.3 访问者模式的实现
具体实现代码如下所示:
1 abstract class Visitor 2 { 3 public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA); 4 5 public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB); 6 } 7 8 class ConcreteVisitor1 : Visitor 9 {10 public override void VisitConcreteElementA(ConcreteElementA concreteElementA)11 {12 Console.WriteLine("{0}被{1}访问", concreteElementA.GetType().Name, this.GetType().Name);13 }14 15 public override void VisitConcreteElementB(ConcreteElementB concreteElementB)16 {17 Console.WriteLine("{0}被{1}访问", concreteElementB.GetType().Name, this.GetType().Name);18 }19 }20 21 class ConcreteVisitor2 : Visitor22 {23 public override void VisitConcreteElementA(ConcreteElementA concreteElementA)24 {25 Console.WriteLine("{0}被{1}访问", concreteElementA.GetType().Name, this.GetType().Name);26 }27 28 public override void VisitConcreteElementB(ConcreteElementB concreteElementB)29 {30 Console.WriteLine("{0}被{1}访问", concreteElementB.GetType().Name, this.GetType().Name);31 }32 }33 34 abstract class Element35 {36 public abstract void Accept(Visitor visitor);37 }38 39 class ConcreteElementA : Element40 {41 public override void Accept(Visitor visitor)42 {43 visitor.VisitConcreteElementA(this);44 }45 46 public void OperationA()47 { }48 }49 50 class ConcreteElementB : Element51 {52 public override void Accept(Visitor visitor)53 {54 visitor.VisitConcreteElementB(this);55 }56 57 public void OperationB()58 { }59 }60 61 class ObjectStructure62 {63 private IListelements = new List ();64 65 public void Attach(Element element)66 {67 elements.Add(element);68 }69 70 public void Detach(Element element)71 {72 elements.Remove(element);73 }74 75 public void Accept(Visitor visitor)76 {77 foreach (Element e in elements)78 {79 e.Accept(visitor);80 }81 }82 }
主程序示例如下:
1 static void Main(string[] args) 2 { 3 ObjectStructure o = new ObjectStructure(); 4 o.Attach(new ConcreteElementA()); 5 o.Attach(new ConcreteElementB()); 6 7 ConcreteVisitor1 v1 = new ConcreteVisitor1(); 8 ConcreteVisitor2 v2 = new ConcreteVisitor2(); 9 10 o.Accept(v1);11 o.Accept(v2);12 13 Console.Read();14 }
二、访问者模式的应用场景
每个设计模式都有其应当使用的情况,那让我们看看访问者模式具体应用场景。如果遇到以下场景,此时我们可以考虑使用访问者模式。
- 如果系统有比较稳定的数据结构,而又有易于变化的算法时,此时可以考虑使用访问者模式。因为访问者模式使得算法操作的添加比较容易。
- 如果一组类中,存在着相似的操作,为了避免出现大量重复的代码,可以考虑把重复的操作封装到访问者中。(当然也可以考虑使用抽象类了)
- 如果一个对象存在着一些与本身对象不相干,或关系比较弱的操作时,为了避免操作污染这个对象,则可以考虑把这些操作封装到访问者对象中。
三、访问者模式的优缺点
访问者模式具有以下优点:
- 访问者模式使得添加新的操作变得容易。如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,添加新的操作会变得很复杂。而使用访问者模式,增加新的操作就意味着添加一个新的访问者类。因此,使得添加新的操作变得容易。
- 访问者模式使得有关的行为操作集中到一个访问者对象中,而不是分散到一个个的元素类中。这点类似与"中介者模式"。
- 访问者模式可以访问属于不同的等级结构的成员对象,而迭代只能访问属于同一个等级结构的成员对象。
访问者模式也有如下的缺点:
- 增加新的元素类变得困难。每增加一个新的元素意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中添加相应的具体操作。
四、总结
访问者模式是用来封装一些施加于某种数据结构之上的操作。它使得可以在不改变元素本身的前提下增加作用于这些元素的新操作,访问者模式的目的是把操作从数据结构中分离出来。