場景:長途汽車票、火車票價格調整
描述:春運開始了,人流高峰期,打工的人群要回家過年了,票價要漲了!
1、抽象通路者(Visitor,程式中為:NotifyVisitor)角色:聲明了一個或者多個通路操作,形成所有的具體元素角色必須實作的接口。
2、具體通路者(ConcreteVisitor,程式中為各個期間的票價浮動情況)角色:實作抽象通路者角色所聲明的接口,也就是抽象通路者所聲明的各個通路操作。
3、抽象節點(Element,程式中的交通工具基類)角色:聲明一個接受操作,接受一個通路者對象作為一個參量。
4、具體節點(ConcreteElement,程式中的各類交通工具)角色:實作了抽象元素所規定的接受操作。
5、結構對象(ObiectStructure,程式中的交通管理部門)角色:有如下的一些責任,可以周遊結構中的所有元素;如果需要,提供一個高層次的接口讓通路者對象可以通路每一個元素;如果需要,可以設計成一個複合對象或者一個聚集,如列(List)或集合(Set)。
在軟體建構過程中,由于需求的改變,某些類層次結構中常常需要增加新的行為(方法),如果直接在基類中做這樣的改變,将會給子類帶來很繁重的變更負擔,甚至破壞原有設計。
如何在不更改類層次結構的前提下,在運作時根據需要透明的為類層次結構上的各個類動态添加新的操作,進而避免上述問題?
辨別一個作用于某對象結構中的各元素的操作。它可以在不改變各元素的類的前提下定義作用于這些元素的新的操作。
實作1:在不使用通路者的時候
(一)交通工具标準
//交通工具
public abstract class Vehicle
{
public abstract void ShowPrice();
//過年漲價
public abstract void PriceFloatup();
}
(二)長途汽車與火車
//bus
public class Bus : Vehicle
public override void ShowPrice()
{
Console.WriteLine("長途汽車石家莊到邢台50元");
}
public override void PriceFloatup()
Console.WriteLine("春運開始了,汽車票在原價的基礎上,上浮20%!");
//train
public class Train : Vehicle
Console.WriteLine("火車石家莊到邢台40元");
Console.WriteLine("春運開始了,火車票在原價的基礎上,上浮15%!");
(三)測試
Bus bus = new Bus();
bus.ShowPrice();
bus.PriceFloatup();
Train train = new Train();
train.ShowPrice();
train.PriceFloatup();
結果:
長途汽車石家莊到邢台50元
春運開始了,汽車票在原價的基礎上,上浮20%!
火車石家莊到邢台40元
春運開始了,火車票在原價的基礎上,上浮15%!
(四)特殊的日子,漲價
國慶期間,票價也要漲!
現在要在長途與火車中添加新的漲價通知。那麼在基類中添加接口:
//國慶漲價
public abstract void PriceNationdayFloatup();
在兩個實作中添加實作:
public override void PriceNationdayFloatup()
Console.WriteLine("國慶期間,汽車票在原價的基礎上,上浮5%!");
……
Console.WriteLine("國慶期間,火車票在原價的基礎上,上浮3%!");
}
(五)測試
bus.PriceNationdayFloatup();
train.PriceNationdayFloatup();
結果:
國慶期間,汽車票在原價的基礎上,上浮5%!
國慶期間,火車票在原價的基礎上,上浮3%!
如果将來國家生産力高度發達,票價下調,那麼,還要在兩個類實作的基礎上添加各自的通知方法。
現在以通路者來實作整個通知系統。
(一)通路者抽象
漲價總是變,在不同的時期,總是要漲價。是以價格因素這裡為通路者。
//上面的通知,漲價
public abstract class NotifyVisitor
public abstract void Visit(Bus bus);
public abstract void Visit(Train train);
(二)客運部門
長途汽車,火車部門接受通路者的通知。
public abstract void Accept(NotifyVisitor visitor);
(三) 客運部門實作
public override void Accept(NotifyVisitor visitor)
visitor.Visit(this);
(四)春運要漲價
這是一個實作的通路者
public class NewYearVisitor : NotifyVisitor
public override void Visit(Bus bus)
{
bus.ShowPrice();
public override void Visit(Train train)
train.ShowPrice();
}
它的目的就是通知兩個部門,要漲價及漲價的細節。
(五)交通管理部門
用于确定要漲價的部門。這是可配置設定的:交通工具有很多種,長途汽車與火車是其中的兩種,這次是兩者都要漲!
public class TraffiMnagement
IList<Vehicle> _list = new List<Vehicle>();
public void Add(Vehicle vehicle)
_list.Add(vehicle);
public void Detach(Vehicle vehicle)
_list.Remove(vehicle);
public void Accept(NotifyVisitor visitor)
foreach (Vehicle vv in _list)
{
vv.Accept(visitor);
}
(六)測試
public void TestVisitor()
TraffiMnagement department = new TraffiMnagement();
department.Add(new Bus());
department.Add(new Train());
department.Accept(new NewYearVisitor());
(七) 國慶期間漲價
新加國慶通路者,其它的不用變動。
public class NationalDayNotifyVisitor : NotifyVisitor
bus.ShowPrice();
Console.WriteLine("國慶節期間,汽車票在原價的基礎上,上浮5%!");
Console.WriteLine("國慶節期間,火車票在原價的基礎上,上浮3%!");
(八)測試
department.Accept(new NationalDayNotifyVisitor());
國慶節期間,汽車票在原價的基礎上,上浮5%!
國慶節期間,火車票在原價的基礎上,上浮3%!
(九)生産力發達了,票價要降了!
新加 願望通路者。
public class WillVisitor : NotifyVisitor
Console.WriteLine("生産力發達了人民幸福了,汽車票在原價的基礎上,下調90%!");
Console.WriteLine("生産力發達了人民幸福了,火車票在原價的基礎上,下調90%!");
(十)測試
department.Accept(new WillVisitor());
生産力發達了人民幸福了,汽車票在原價的基礎上,下調90%!
生産力發達了人民幸福了,火車票在原價的基礎上,下調90%!
Visitor模式通過所謂的雙重分發(double dispatch)來實作在不更改Element類層次結構的前提下,在運作時透明的為類層次結構上的各個類動态添加新的操作。所謂雙重分發即Visitor模式中間包括了兩個多态分發:第一個為Accept方法的多态辨析;第二個為Visit方法的多态辨析(重載)
Visitor模式最大缺點在于擴充類層次結構(添加新的Element子類),會導緻Visitor類的改變,是以Visitor模式使使用者Element類層子結構穩定,而其中的操作卻經常面臨頻繁改動。
當我們需要增加一個交通工具的子類時,我們需要給NotifyVisitor類添加一個Visit函數,并且NotifyVisitor的每個派生類也必須添加。
部落格園大道至簡
<a href="http://www.cnblogs.com/jams742003/" target="_blank">http://www.cnblogs.com/jams742003/</a>
轉載請注明:部落格園