意图intent:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
适用性:
- 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
- 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
Definition:
Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
participants
The classes and/or objects participating in this pattern are:
- Visitor (Visitor)
- declares a Visit operation for each class of ConcreteElement in the object structure. The operation's name and signature identifies the class that sends the Visit request to the visitor. That lets the visitor determine the concrete class of the element being visited. Then the visitor can access the elements directly through its particular interface
- ConcreteVisitor (IncomeVisitor, VacationVisitor)
- implements each operation declared by Visitor. Each operation implements a fragment of the algorithm defined for the corresponding class or object in the structure. ConcreteVisitor provides the context for the algorithm and stores its local state. This state often accumulates results during the traversal of the structure.
- Element (Element)
- defines an Accept operation that takes a visitor as an argument.
- ConcreteElement (Employee)
- implements an Accept operation that takes a visitor as an argument
- ObjectStructure (Employees)
- can enumerate its elements
- may provide a high-level interface to allow the visitor to visit its elements
- may either be a Composite (pattern) or a collection such as a list or a set
在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设计。如何在不更改类层次结构的前提下,在运行时根据需要透明地为类层次结构上的各个类动态添加新的操作,从而避免上述问题?
Visitor模式通过所谓双重分发(double dispatch)来实现在不更改element类层次结构的前提下,在运行时透明地为类层次结构上的各个类动态添加新的操作。所谓双重分发即visitor模式中间包括了两个多态分发(注意其中的多态机制):第一个为accept方法的多态辨析;第二个为visit方法的多态辨析。Visitor模式的最大缺点在于扩展类层次结构(增添新的element子类),会导致visitor类的改变。因此visitor模式适用于element类层次结构稳定,而其中的操作却经常面临频繁改动。
Sample code in c#
This structural code demonstrates the Visitor pattern in which an object traverses an object structure and performs the same operation on each node in this structure. Different visitor objects define different operations.
// Visitor pattern -- Structural example |
using System; namespace DoFactory.GangOfFour.Visitor.Structural class MainApp // Create visitor objects // Structure accepting visitors // Wait for user // "Visitor" abstract class Visitor // "ConcreteVisitor1" class ConcreteVisitor1 : Visitor public override void VisitConcreteElementB( // "ConcreteVisitor2" class ConcreteVisitor2 : Visitor public override void VisitConcreteElementB( // "Element" abstract class Element // "ConcreteElementA" class ConcreteElementA : Element public void OperationA() // "ConcreteElementB" class ConcreteElementB : Element public void OperationB() // "ObjectStructure" class ObjectStructure public void Attach(Element element) public void Detach(Element element) public void Accept(Visitor visitor) |
Output
ConcreteElementA visited by ConcreteVisitor1
ConcreteElementB visited by ConcreteVisitor1
ConcreteElementA visited by ConcreteVisitor2
ConcreteElementB visited by ConcreteVisitor2
This real-world code demonstrates the Visitor pattern in which two objects traverse a list of Employees and performs the same operation on each Employee. The two visitor objects define different operations -- one adjusts vacation days and the other income.
// Visitor pattern -- Real World example |
using System; namespace DoFactory.GangOfFour.Visitor.RealWorld class MainApp // Employees are 'visited' // Wait for user // "Visitor" interface IVisitor // "ConcreteVisitor1" class IncomeVisitor : IVisitor // Provide 10% pay raise // "ConcreteVisitor2" class VacationVisitor : IVisitor class Clerk : Employee class Director : Employee class President : Employee // "Element" abstract class Element // "ConcreteElement" class Employee : Element // Constructor // Properties public double Income public int VacationDays public override void Accept(IVisitor visitor) // "ObjectStructure" class Employees public void Attach(Employee employee) public void Detach(Employee employee) public void Accept(IVisitor visitor) |
Output
Clerk Hank's new income: $27,500.00
Director Elly's new income: $38,500.00
President Dick's new income: $49,500.00
Clerk Hank's new vacation days: 14
Director Elly's new vacation days: 16
President Dick's new vacation days: 21