場景:長途汽車票、火車票價格調整 ide
描述:春運開始了,人流高峯期,打工的人羣要回家過年了,票價要漲了! 函數
一、抽象訪問者(Visitor,程序中爲:NotifyVisitor)角色:聲明瞭一個或者多個訪問操做,造成全部的具體元素角色必須實現的接口。 工具
二、具體訪問者(ConcreteVisitor,程序中爲各個期間的票價浮動狀況)角色:實現抽象訪問者角色所聲明的接口,也就是抽象訪問者所聲明的各個訪問操做。 測試
三、抽象節點(Element,程序中的交通工具基類)角色:聲明一個接受操做,接受一個訪問者對象做爲一個參量。 this
四、具體節點(ConcreteElement,程序中的各種交通工具)角色:實現了抽象元素所規定的接受操做。 spa
五、結構對象(ObiectStructure,程序中的交通管理部門)角色:有以下的一些責任,能夠遍歷結構中的全部元素;若是須要,提供一個高層次的接口讓訪問者對象能夠訪問每個元素;若是須要,能夠設計成一個複合對象或者一個彙集,如列(List)或集合(Set)。 設計
在軟件構建過程當中,因爲需求的改變,某些類層次結構中經常須要增長新的行爲(方法),若是直接在基類中作這樣的改變,將會給子類帶來很繁重的變動負擔,甚至破壞原有設計。
如何在不更改類層次結構的前提下,在運行時根據須要透明的爲類層次結構上的各個類動態添加新的操做,從而避免上述問題?
標識一個做用於某對象結構中的各元素的操做。它能夠在不改變各元素的類的前提下定義做用於這些元素的新的操做。 對象
實現1:在不使用訪問者的時候 接口
(一)交通工具標準 it
//交通工具
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
{
public override void ShowPrice()
{
Console.WriteLine("火車石家莊到邢臺40元");
}
public override void PriceFloatup()
{
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%!");
}
……
public override void PriceNationdayFloatup()
{
Console.WriteLine("國慶期間,火車票在原價的基礎上,上浮3%!");
}
(五)測試
Bus bus = new Bus();
bus.ShowPrice();
bus.PriceNationdayFloatup();
Train train = new Train();
train.ShowPrice();
train.PriceNationdayFloatup();
結果:
長途汽車石家莊到邢臺50元
國慶期間,汽車票在原價的基礎上,上浮5%!
火車石家莊到邢臺40元
國慶期間,火車票在原價的基礎上,上浮3%!
若是未來國家生產力高度發達,票價下調,那麼,還要在兩個類實現的基礎上添加各自的通知方法。
如今以訪問者來實現整個通知系統。
(一)訪問者抽象
漲價老是變,在不一樣的時期,老是要漲價。因此價格因素這裏爲訪問者。
//上面的通知,漲價
public abstract class NotifyVisitor
{
public abstract void Visit(Bus bus);
public abstract void Visit(Train train);
}
(二)客運部門
長途汽車,火車部門接受訪問者的通知。
//交通工具
public abstract class Vehicle
{
public abstract void ShowPrice();
//過年漲價
public abstract void Accept(NotifyVisitor visitor);
}
(三) 客運部門實現
//bus
public class Bus : Vehicle
{
public override void ShowPrice()
{
Console.WriteLine("長途汽車石家莊到邢臺50元");
}
public override void Accept(NotifyVisitor visitor)
{
visitor.Visit(this);
}
}
//train
public class Train : Vehicle
{
public override void ShowPrice()
{
Console.WriteLine("火車石家莊到邢臺40元");
}
public override void Accept(NotifyVisitor visitor)
{
visitor.Visit(this);
}
}
(四)春運要漲價
這是一個實現的訪問者
public class NewYearVisitor : NotifyVisitor
{
public override void Visit(Bus bus)
{
bus.ShowPrice();
Console.WriteLine("春運開始了,汽車票在原價的基礎上,上浮20%!");
}
public override void Visit(Train train)
{
train.ShowPrice();
Console.WriteLine("春運開始了,火車票在原價的基礎上,上浮15%!");
}
}
它的目的就是通知兩個部門,要漲價及漲價的細節。
(五)交通管理部門
用於肯定要漲價的部門。這是可分配的:交通工具備不少種,長途汽車與火車是其中的兩種,此次是二者都要漲!
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());
}
結果:
長途汽車石家莊到邢臺50元
春運開始了,汽車票在原價的基礎上,上浮20%!
火車石家莊到邢臺40元
春運開始了,火車票在原價的基礎上,上浮15%!
(七) 國慶期間漲價
新加國慶訪問者,其它的不用變更。
public class NationalDayNotifyVisitor : NotifyVisitor
{
public override void Visit(Bus bus)
{
bus.ShowPrice();
Console.WriteLine("國慶節期間,汽車票在原價的基礎上,上浮5%!");
}
public override void Visit(Train train)
{
train.ShowPrice();
Console.WriteLine("國慶節期間,火車票在原價的基礎上,上浮3%!");
}
}
(八)測試
public void TestVisitor()
{
TraffiMnagement department = new TraffiMnagement();
department.Add(new Bus());
department.Add(new Train());
department.Accept(new NationalDayNotifyVisitor());
}
結果:
長途汽車石家莊到邢臺50元
國慶節期間,汽車票在原價的基礎上,上浮5%!
火車石家莊到邢臺40元
國慶節期間,火車票在原價的基礎上,上浮3%!
(九)生產力發達了,票價要降了!
新加 願望訪問者。
public class WillVisitor : NotifyVisitor
{
public override void Visit(Bus bus)
{
bus.ShowPrice();
Console.WriteLine("生產力發達了人民幸福了,汽車票在原價的基礎上,下調90%!");
}
public override void Visit(Train train)
{
train.ShowPrice();
Console.WriteLine("生產力發達了人民幸福了,火車票在原價的基礎上,下調90%!");
}
}
(十)測試
public void TestVisitor()
{
TraffiMnagement department = new TraffiMnagement();
department.Add(new Bus());
department.Add(new Train());
department.Accept(new WillVisitor());
}
結果:
長途汽車石家莊到邢臺50元
生產力發達了人民幸福了,汽車票在原價的基礎上,下調90%!
火車石家莊到邢臺40元
生產力發達了人民幸福了,火車票在原價的基礎上,下調90%!
Visitor模式經過所謂的雙重分發(double dispatch)來實如今不更改Element類層次結構的前提下,在運行時透明的爲類層次結構上的各個類動態添加新的操做。所謂雙重分發即Visitor模式中間包括了兩個多態分發:第一個爲Accept方法的多態辨析;第二個爲Visit方法的多態辨析(重載) Visitor模式最大缺點在於擴展類層次結構(添加新的Element子類),會致使Visitor類的改變,所以Visitor模式使用戶Element類層子結構穩定,而其中的操做卻常常面臨頻繁改動。 當咱們須要增長一個交通工具的子類時,咱們須要給NotifyVisitor類添加一個Visit函數,而且NotifyVisitor的每一個派生類也必須添加。