场景:长途汽车票、火车票价格调整 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的每一个派生类也必须添加。