Visitor(访问者)
实现
实现方式(一):Visitor模式结构样式代码。
实现方式(二):使用Visitor模式解构设计。
实现方式(三):使用AcyclicVisitor模式解构设计。
意图
表示一个作用于某对象结构中的各元素的操作。
Visitor使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
Representanoperationtobeperformedontheelementsofanobjectstructure.
Visitorletsyoudefineanewoperationwithoutchangingtheclassesoftheelementsonwhichitoperates.
Visitor
为该对象结构中ConcreteElement的每一个类声明一个Visit操作。该操作的名字和特征标识了发送Visit请求给该访问者的那个类。
ConcreteVisitor
实现每个由Visitor声明的操作。
Element
定义一个Accept操作,它以一个Visitor为参数。
ConcreteElement
实现Accept操作,该操作以一个Visitor为参数。
ObjectStructure
能枚举Element。
可以提供一个高层的接口以允许该Visitor访问它的元素。
可以是一个Composite或是一个集合、列表或无序集合。
适用性
在以下情况下可以使用Visitor模式:
一个对象结构包含很多类操作,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作污染这些对象的类。
定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。
缺点
增加新的ConcreteElement类很困难。添加新的ConcreteElement都要在Visitor中添加一个新的抽象操作。
可能破坏封装。Visitor假定ConcreteElement接口的功能足够强,足以让Visitor进行它的工作。但有时会迫使你提供ConcreteElement的内部状态的公共操作。
效果
Visitor模式使得易于增加新的操作。
Visitor集中相关的操作而分离无关的操作。
相关模式
Visitor可以用于对一个Composite模式定义的对象结构进行操作。
Visitor可以用于Interpreter解释。
实现
实现方式(一):Visitor模式结构样式代码。
复制代码
1namespaceVisitorPattern.Implementation1
2{
3publicabstractclassElement
4{
5publicabstractvoidAccept(Visitorvisitor);
6}
7
8publicabstractclassVisitor
9{
10publicabstractvoidVisit(ConcreteElementAelement);
11publicabstractvoidVisit(ConcreteElementBelement);
12}
13
14publicclassObjectStructure
15{
16privateList_elements=newList();
17
18publicvoidAttach(Elementelement)
19{
20_elements.Add(element);
21}
22
23publicvoidDetach(Elementelement)
24{
25_elements.Remove(element);
26}
27
28publicvoidAccept(Visitorvisitor)
29{
30foreach(varelementin_elements)
31{
32element.Accept(visitor);
33}
34}
35}
36
37publicclassConcreteElementA:Element
38{
39publicstringName{get;set;}
40
41publicoverridevoidAccept(Visitorvisitor)
42{
43visitor.Visit(this);
44}
45}
46
47publicclassConcreteElementB:Element
48{
49publicstringID{get;set;}
50
51publicoverridevoidAccept(Visitorvisitor)
52{
53visitor.Visit(this);
54}
55}
56
57publicclassConcreteVisitorA:Visitor
58{
59publicoverridevoidVisit(ConcreteElementAelement)
60{
61Console.WriteLine(
62"ConcreteVisitorAvisitedConcreteElementA:{0}",
63element.Name);
64}
65
66publicoverridevoidVisit(ConcreteElementBelement)
67{
68Console.WriteLine(
69"ConcreteVisitorAvisitedConcreteElementB:{0}",
70element.ID);
71}
72}
73
74publicclassConcreteVisitorB:Visitor
75{
76publicoverridevoidVisit(ConcreteElementAelement)
77{
78Console.WriteLine(
79"ConcreteVisitorBvisitedConcreteElementA:{0}",
80element.Name);
81}
82
83publicoverridevoidVisit(ConcreteElementBelement)
84{
85Console.WriteLine(
86"ConcreteVisitorBvisitedConcreteElementB:{0}",
87element.ID);
88}
89}
90
91publicclassClient
92{
93publicvoidTestCase1()
94{
95varobjectStructure=newObjectStructure();
96
97objectStructure.Attach(newConcreteElementA());
98objectStructure.Attach(newConcreteElementB());
99
100objectStructure.Accept(newConcreteVisitorA());
101objectStructure.Accept(newConcreteVisitorB());
102}
103}
104}
复制代码
实现方式(二):使用Visitor模式解构设计。
假设我们有一个Employee类,Employee分为按时薪计算的Employee和按月薪计算的Employee。
复制代码
1publicclassEmployee
2{
3publicabstractstringGetHoursAndPayReport();
4}
5
6publicclassHourlyEmployee:Employee
7{
8publicoverridestringGetHoursAndPayReport()
9{
10//generatethelineforthishourlyemployee
11return"100Hoursand$1000intotal.";
12}
13}
14
15publicclassSalariedEmployee:Employee
16{
17publicoverridestringGetHoursAndPayReport()
18{
19//donothing
20returnstring.Empty;
21}
22}
复制代码
这段代码的问题是,Employee类及子类耦合了SalaryReport相关的职责,这侵犯了单一职责原则(SingleResponsibilityPrinciple),因为其导致每次需要更改Report相关的职责时,都需要修改Employee类。
我们是用Visitor模式来解决这个问题。
复制代码
1namespaceVisitorPattern.Implementation2
2{
3publicabstractclassEmployee
4{
5publicabstractstringAccept(EmployeeVisitorvisitor);
6}
7
8publicclassHourlyEmployee:Employee
9{
10publicoverridestringAccept(EmployeeVisitorvisitor)
11{
12returnvisitor.Visit(this);
13}
14}
15
16publicclassSalariedEmployee:Employee
17{
18publicoverridestringAccept(EmployeeVisitorvisitor)
19{
20returnvisitor.Visit(this);
21}
22}
23
24publicabstractclassEmployeeVisitor
25{
26publicabstractstringVisit(HourlyEmployeeemployee);
27publicabstractstringVisit(SalariedEmployeeemployee);
28}
29
30publicclassHoursPayReport:EmployeeVisitor
31{
32publicoverridestringVisit(HourlyEmployeeemployee)
33{
34//generatethelineofthereport.
35return"100Hoursand$1000intotal.";
36}
37
38publicoverridestringVisit(SalariedEmployeeemployee)
39{
40//donothing
41returnstring.Empty;
42}
43}
44}
复制代码
实现方式(三):使用AcyclicVisitor模式解构设计。
我们注意到Employee类依赖于EmployeeVisitor基类。而EmployeeVisitor类为每个Employee的子类都提供了一个Visit方法。
因此,这里形成了一个依赖关系的环。这导致Visitor在响应变化时变得复杂。
Visitor模式在类继承关系不是经常变化时可以工作的很好,但在子类衍生频繁的情况下会增加复杂度。
此时,我们可以应用AcyclicVisitor模式,抽象出窄接口,以使Employee子类仅依赖于该窄接口。
复制代码
1namespaceVisitorPattern.Implementation3
2{
3publicabstractclassEmployee
4{
5publicabstractstringAccept(EmployeeVisitorvisitor);
6}
7
8publicclassHourlyEmployee:Employee
9{
10publicoverridestringAccept(EmployeeVisitorvisitor)
11{
12try
13{
14IHourlyEmployeeVisitorhourlyEmployeeVisitor=(IHourlyEmployeeVisitor)visitor;
15returnhourlyEmployeeVisitor.Visit(this);
16}
17catch(InvalidCastExceptionex)
18{
19Console.WriteLine(ex.Message);
20}
21
22returnstring.Empty;
23}
24}
25
26publicclassSalariedEmployee:Employee
27{
28publicoverridestringAccept(EmployeeVisitorvisitor)
29{
30try
31{
32ISalariedEmployeeVisitorsalariedEmployeeVisitor=(ISalariedEmployeeVisitor)visitor;
33returnsalariedEmpwww.wang027.comloyeeVisitor.Visit(this);
34}
35catch(InvalidCastExceptionex)
36{
37Console.WriteLine(ex.Message);
38}
39
40returnstring.Empty;
41}
42}
43
44publicinterfaceIHourlyEmployeeVisitor
45{
46stringVisit(HourlyEmployeeemployee);
47}
48
49publicinterfaceISalariedEmployeeVisitor
50{
51stringVisit(SalariedEmployeeemployee);
52}
53
54publicabstractclassEmployeeVisitor
55{
56}
57
58publicclassHoursPayReport:EmployeeVisitor,IHourlyEmployeeVisitor
59{
60publicstringVisit(HourlyEmployeeemployee)
61{
62//generatethelineofthereport.
63return"100Hoursand$1000intotal.";
64}
65}
66
67publicclassSalariedPayReport:EmployeeVisitor,ISalariedEmployeeVisitor
68{
69publicstringVisit(SalariedEmployeeemployee)
70{
71return"Something";
72}
73}
74}
复制代码
|
|