40访问者模式(Visitor Pattern)
類層次結構的變化:
??? 類層次結構中可能經常由于引入新的操作,從而將類型變得脆弱...
??? ???????????????????????
動機:
??? 在軟件構建過程中,由于需求的改變,某些類層次結構中常常需要增加新的行為(方法),如果直接在基類中做這樣的更改,將會給子類帶來很繁重的變更負擔,甚至破壞原有設計。
??? 如何在不更改類層次結構的前提下,在運行時根據需要透明地為類層次結構上的各個類動態添加新的操作,從而避免上述問題?
意圖:
??? 表示一個作用于某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這引起元素的新操作。
結構:
??? ?? ?? ???
適用性:
??? 1.一個對象結構包含很多類對象,它們有不同的接口,而你想對這些對象實施一些依賴于其具體類的操作。
??? 2.需要對一個對象結構中的對象進行很多不同的并且不相關的操作,而你想避免讓這些操作"污染"這些對象的類。Visitor使得你可以將相關的操作集中起來定義在一個類中。當該對象結構被很多應用共享時,用Visitor模式讓每個應用僅包含需要用到的操作。
??? 3.定義對象結構的類很少改變,但經常需要在結構上定義新的操作。改變對象結構類需要重定義對所有訪問者的接口,這可能需要很大的代價。如果對象結構類經常改變,那么可能還是在這些類中定義這些操作較好。
代碼實現:
????
??1?//?MainApp?startup?application
??2?
??3???class?MainApp
??4???{
??5?????static?void?Main()
??6?????{
??7???????//?Setup?employee?collection
??8???????Employees?e?=?new?Employees();
??9???????e.Attach(new?Clerk());
?10???????e.Attach(new?Director());
?11???????e.Attach(new?President());
?12?
?13???????//?Employees?are?'visited'
?14???????e.Accept(new?IncomeVisitor());
?15???????e.Accept(new?VacationVisitor());
?16?
?17???????//?Wait?for?user
?18???????Console.Read();
?19?????}
?20???}
?21?
?22???//?"Visitor"
?23?
?24???interface?IVisitor
?25???{
?26?????void?Visit(Element?element);
?27???}
?28?
?29???//?"ConcreteVisitor1"
?30?
?31???class?IncomeVisitor?:?IVisitor
?32???{
?33?????public?void?Visit(Element?element)
?34?????{
?35???????Employee?employee?=?element?as?Employee;
?36?
?37???????//?Provide?10%?pay?raise
?38???????employee.Income?*=?1.10;
?39???????Console.WriteLine("{0}?{1}'s?new?income:?{2:C}",
?40?????????employee.GetType().Name,?employee.Name,
?41?????????employee.Income);
?42?????}
?43???}
?44?
?45???//?"ConcreteVisitor2"
?46?
?47???class?VacationVisitor?:?IVisitor
?48???{
?49?????public?void?Visit(Element?element)
?50?????{
?51???????Employee?employee?=?element?as?Employee;
?52???????
?53???????//?Provide?3?extra?vacation?days
?54???????Console.WriteLine("{0}?{1}'s?new?vacation?days:?{2}",
?55?????????employee.GetType().Name,?employee.Name,
?56?????????employee.VacationDays);
?57?????}
?58???}
?59?
?60???class?Clerk?:?Employee
?61???{
?62?????//?Constructor
?63?????public?Clerk()?:?base("Hank",?25000.0,?14)
?64?????{
?65?????}
?66???}
?67?
?68???class?Director?:?Employee
?69???{
?70?????//?Constructor
?71?????public?Director()?:?base("Elly",?35000.0,?16)
?72?????{??
?73?????}
?74???}
?75?
?76???class?President?:?Employee
?77???{
?78?????//?Constructor
?79?????public?President()?:?base("Dick",?45000.0,?21)
?80?????{??
?81?????}
?82???}
?83?
?84???//?"Element"
?85?
?86???abstract?class?Element
?87???{
?88?????public?abstract?void?Accept(IVisitor?visitor);
?89???}
?90?
?91???//?"ConcreteElement"
?92?
?93???class?Employee?:?Element
?94???{
?95?????string?name;
?96?????double?income;
?97?????int?vacationDays;
?98?
?99?????//?Constructor
100?????public?Employee(string?name,?double?income,
101???????int?vacationDays)
102?????{
103???????this.name?=?name;
104???????this.income?=?income;
105???????this.vacationDays?=?vacationDays;
106?????}
107?
108?????//?Properties
109?????public?string?Name
110?????{
111???????get{?return?name;?}
112???????set{?name?=?value;?}
113?????}
114?
115?????public?double?Income
116?????{
117???????get{?return?income;?}
118???????set{?income?=?value;?}
119?????}
120?
121?????public?int?VacationDays
122?????{
123???????get{?return?vacationDays;?}
124???????set{?vacationDays?=?value;?}
125?????}
126?
127?????public?override?void?Accept(IVisitor?visitor)
128?????{
129???????visitor.Visit(this);
130?????}
131???}
132?
133???//?"ObjectStructure"
134?
135???class?Employees
136???{
137?????private?ArrayList?employees?=?new?ArrayList();
138?
139?????public?void?Attach(Employee?employee)
140?????{
141???????employees.Add(employee);
142?????}
143?
144?????public?void?Detach(Employee?employee)
145?????{
146???????employees.Remove(employee);
147?????}
148?
149?????public?void?Accept(IVisitor?visitor)
150?????{
151???????foreach?(Employee?e?in?employees)
152???????{
153?????????e.Accept(visitor);
154???????}
155???????Console.WriteLine();
156?????}
157???}
運行結果:
??? ???
Visoitr模式的幾個要點:
??? 1.Visitor模式通過所謂雙重分發(double dispatch)來實現在不更改Element類層次結構的前提下,在運行時透明地為類層次結構上的各個類動態添加新的操作。
??? 2.所謂雙重分發卻Visotor模式中間包括了兩個多態分發(注意其中的多態機制);第一個為accept方法的多態辨析;第二個為visitor方法的多態辨析。
??? 3.Visotor模式的最大缺點在于擴展類層次結構(增添新的Element子類),會導致Visitor類的改變。因此Visiotr模式適用"Element"類層次結構穩定,而其中的操作卻經常面臨頻繁改動".
總結
以上是生活随笔為你收集整理的40访问者模式(Visitor Pattern)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 银行有没有告诉你,按这个方法存钱,每月的
- 下一篇: 第五节:WebApi的三大过滤器