模式实例之——访问者实例
场景:长途汽车票、火车票价格调整
描述:春运开始了,人流高峰期,打工的人群要回家过年了,票价要涨了!
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
{
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的每个派生类也必须添加。
转载于:https://www.cnblogs.com/jams742003/archive/2010/01/04/1638715.html
模式实例之——访问者实例相关推荐
- sql中如何统计各种零件的总数量_如何应用GOF设计模式中的构建者模式创建复合对象实例...
软件项目实训及课程设计指导--如何应用GOF设计模式中的构建者模式创建复合对象实例 1.GOF设计模式中的构建者模式 构建者设计模式能够将一个复杂对象(它一般为组合类)的构建过程与它的表示部件相互分离 ...
- redis实例python_生产消费者模式与python+redis实例运用(基础篇)
根据这个图,我们举个简单的例子:假如你去某个餐厅吃饭,点了很多菜,厨师要一个一个菜的做,一个厨师不可能同时做出所有你点的菜,于是你有两个选择:第一个,厨师把所有菜都上齐了,你才开始吃:还有一个选择,做 ...
- python设计模式案例分析_Python设计模式之职责链模式原理与用法实例分析
本文实例讲述了Python设计模式之职责链模式原理与用法.分享给大家供大家参考,具体如下: 职责链模式(Chain Of Responsibility):使多个对象都有机会处理请求,从而避免发送者和接 ...
- 深入理解原型模式 ——通过复制生成实例
Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去,欢迎建议和指导):github.com/Snailclimb/- 系列文章回顾: 设计模式专栏 深入理解单例模式 深入理解工厂模式 ...
- 桥接模式实例与解析 实例一:模拟毛笔
桥接模式实例与解析 实例一:模拟毛笔 现需要提供大中小3种型号的画笔,能够绘制5种不同颜色,如果使用蜡笔,我们需要准备3*5=15支蜡笔,也就是说必须准备15个具体的蜡笔类.而 ...
- 简单工厂和工厂方法模式(附简单实例)
工厂模式: 工厂模式是常用的一类创建型设计模式,通常工厂模式是指工厂方法模式.其是使用频率最高的工厂模式. 上图几种工厂模式由简到难: 简单工厂模式定义:定义一个工厂类,其可以根据参数的不同返回不同类 ...
- alwayson高可用组_AlwaysOn可用性组–如何在集群实例和独立实例之间设置AG(第3部分)
alwayson高可用组 We have already configured our Availability Group, now we need to make it flexible and ...
- mysql 统计存储过程实例_MySQL存储过程实例
一.创建MySQL数据库函数 TCC:无参数,查询fruit表中的所有数据 : TAA:两个参数,查询fruit总共有多少行:查询ids为某个值时水果表的数据 TDD:两个参数,查询ids不等于某个值 ...
- 将谷歌云linux实例转为Windows实例
将谷歌云linux实例转为Windows实例 想用谷歌云搭建英灵神殿的服务器,但是不熟悉Linux,所以把它转换成Windows实例. 使用SSH连接进入root模式 sudo -i 安装wegat ...
最新文章
- Redis安装与源码调试
- 用Servlet获取表单数据
- 永磁电机设计唐任远_新能源汽车的关键技术中钕铁硼永磁同步电机结构设计
- 绘图操作(点,线,多边形,徒手多边形等)
- VTK:PolyData之PointLocatorVisualization
- java 一对一的关系_与休眠一对一关系 - java
- AjAx下拉列表框(SELECT)jquery插件
- 西瓜哥:公有云也“All-Flash”?
- 《Cortex-M0权威指南》之Cortex-M0技术综述
- 留言板小系统程序开发
- win10cmd输入java_win10肿么输入cmd 输入java
- no SSL-C headers found
- “Microsoft C++ 异常: cv::Exception,位于内存位置 0x0000005C8ECFFA80 处。”
- HDU-1869 六度分离
- 计算机上面的ms mr,电脑上的计算器,Mod,MC,MR,MS,M+,M-分别表示什么意思啊...
- 如何升级Windows 11正式版?四种方案都在这里了
- 宿华卸任快手CEO程一笑接替;新思科技扩大与台积公司的战略技术合作 | 全球TMT...
- idea双击打不开我的解决方法
- 计算机有几个无法修改的磁盘,电脑磁盘名称无法修改的解决方法
- urlrewriter 的用法
热门文章
- dockerfile arg_解读三组容易混淆的 Dockerfile 指令
- ajax live search,AJAX Live Search
- wxhtmltopdf 图片路径问题_图片引入路径问题
- python装饰器模式带参数_python 装饰器模式 我的理解
- vfp 界面_VFP之老树新花
- 电脑主板接口_电脑主板接口大全
- Unsupported major.minor version 52.0解决
- RDP协议详细解析(二)
- TensorFlow神经网络(四)手写数字识别
- 好程序员web前端分享web开发概况