visitor模式入门
访问差异类型的集合类--visitor模式入门
一,问题提出
访问同一类型的集合类是我们最常见的事情了,我们工作中这样的代码太常见了。
2 while (ie.hasNext()) {
3 Person p = (Person)ie.next();
4 p.doWork();
5 }
这种访问的特点是集合类中的对象是同一类对象Person,他们拥有功能的方法run,我们调用的恰好是这个共同的方法。
在大部份的情况下,这个是可以的,但在一些复杂的情况,如被访问者的继承结构复杂,被访问者的并不是同一类对象,
也就是说不是继承自同一个根类。方法名也并不相同。例如Java GUI中的事件就是一个例子。
例如这样的问题,有如下类和方法:
类:PA ,方法:runPA();
类:PB ,方法:runPB();
类:PC ,方法:runPC();
类:PD ,方法:runPD();
类:PE ,方法:runPE();
有一个集合类List
List list = new ArrayList();
list.add(new PA());
list.add(new PB());
list.add(new PC());
list.add(new PD());
list.add(new PE());
....
二:解决
要求能访问到每个类的对应的方法。我们第一反应应该是这样的。
2 while (ie.hasNext()) {
3 Object obj = ie.next();
4 if (obj instanceof PA) {
5 ((PA)obj).runPA();
6 } else if (obj instanceof PB) {
7 ((PB)obj).runPB();
8 } else if (obj instanceof PC) {
9 ((PC)obj).runPC();
10 } else if (obj instanceof PD) {
11 ((PD)obj).runPD();
12 } else if (obj instanceof PE) {
13 ((PE)obj).runPE();
14 }
15 }
三:新问题及分析解决
当数目变多的时候,维护if else是个费力气的事情:
仔细分析if,else做的工作,首先判断类型,然後根据类型执行相应的函数
如何才能解决这两个问题呢?首先想到的是java的多态,多态就是根据参数执行相应的内容,
能很容易的解决第二个问题,我们可以写这样一个类:
2 public void run(PA pa) {
3 pa.runPA();
4 }
5 public void run(PB pb) {
6 pb.runPB();
7 }
8 public void run(PC pc) {
9 pc.runPC();
10 }
11 public void run(PD pd) {
12 pd.runPD();
13 }
14 public void run(PE pe) {
15 pe.runPE();
16 }
17 }
这样只要调用run方法,传入对应的参数就能执行了。
还有一个问题就是判断类型。由于重载(overloading)是静态多分配(java语言本身是支持"静态多分配"的。
关于这个概念请看这里)所以造成重载只根据传入对象的定义类型,而不是实际的类型,所以必须在传入前就确定类型,
这可是个难的问题,因为在容器中对象全是Object,出来后要是判断是什么类型必须用
if (xx instanceof xxx)这种方法,如果用这种方法启不是又回到了原点,有没有什么更好的办法呢?
我们知到Java还有另外一个特点,覆写(overriding),而覆写是"动态单分配"的(关于这个概念见这里),
那如何利用这个来实现呢?看下边这个方法:
我们让上边的一些类PA PB PC PD PE都实现一个接口P,加入一个方法,accept();
2 // 把自己传入1
3 v.run( this );
4 }
5 然後在visitor中加入一个方法
6 public void run(P p) {
7 // 把自己传入2
8 p.accept( this );
9 }
10 // 这样你在遍历中可以这样写
11 Visitor v = new Visitor();
12 Iterator ie = list.iterator();
13 while (ie.hasNext()) {
14 P p = (P)ie.next();
15 p.accept(v);
16 }
17 }
首先执行的是"把自己传入2",在这里由于Java的特性,实际执行的是子类的accept(),也就是实际类的accept
然後是"把自己传入1",在这里再次把this传入,就明确类型,ok我们巧妙的利用overriding解决了这个问题
其实归纳一下第二部分,一个关键点是"自己认识自己",是不是很可笑。
其实在计算计技术领域的很多技术上看起来很高深的东西,其实就是现有社会中人的生活方式的一种映射
而且这种方式是简单的不能再简单的方式。上边的全部过程基本上是一个简单的visitor模式实现,visitor模式
已经是设计模式中比较复杂的模式了,但其实原理简单到你想笑。看看下边这个比喻也许你的理解会更深刻。
四:一个帮助理解的比喻:
题目:指挥工人工作
条件:你有10个全能工人,10样相同工作。
需求:做完工作
实现:大喊一声所有人去工作
条件变了,工人不是全能,但是工作相同,ok问题不大
条件再变,工作不是相同,但工人是全能,ok问题不大
以上三种情况在现实生活中是很少发生得,最多的情况是这样:
10个工人,每人会做一种工作,10样工作。你又一份名单Collection)写着谁做什么。但你不认识任何人
这个时候你怎么指挥呢,方案一:
你可以一个个的叫工人,然後问他们名字,认识他们,查名单,告诉他们做什么工作。
你可以直接叫出他们名字,告诉他们干什么,不需要知到他是谁。
看起来很简单。但如果你要指挥10万人呢 ?而且人员是流动的,每天的人不同,你每天拿到一张文档。
其实很简单,最常用的做法是,你把这份名单贴在墙上,然後大喊一声,所有人按照去看,按照自己的分配情况去做。
这里利用的关键点是"所有工人自己认识自己",你不能苛求每个工人会做所有工作,不能苛求所有工作相同,但你
能要求所有工人都认识自己。
再想想我们开始的程序,每个工人对应着PA PB PC PD PE....
所有的工人都使工人P
每个工人会做的东西不一样runPA runPB runPC
你有一份名单Visitor(重载)记录着谁做什么工作。
看完上边这些,你是不是会产生如下的问题:
问题:为什么不把这些方法的方法名做成一样的,那就可以解决了。
例如,我们每个PA ,PB ,PC都加入一个run 方法,然後run内部再调用自己对应的runPx()方法。
答案:有些时候从不同的角度考虑,或者因为实现的复杂度早成很难统一方法名。
例如上边指挥人工作的例子的例子,其实run方法就是大叫一声去工作,因为每个工人只会做一种工作,所以能行
但我们不能要求所有人只能会做一种事情,这个要求很愚蠢。所以如果每个工人会干两种或者多种工作呢,
也就是我PA 有runPA() walkPA()等等方法, PB有runPB() climbPB()等等。。。
这个时候按照名单做事才是最好的办法。
visitor模式入门相关推荐
- 行为模式之Visitor模式
1.意图 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作 2.适用性 (1)一个对象结构包含很多类对象,它们有不同的接口,而你想对这些实施一些 ...
- 设计模式--访问器(Visitor)模式
模式定义 表示一个作用于某对象结构中的各元素的操作,使得可以在不改变(稳定)各元素的类的前提下定义(扩展)作用于这些元素的新操作(变化) 类图 要点总结 Visitor模式通过所谓双重分发(doubl ...
- 设计模式学习笔记——访问者(Visitor)模式
设计模式学习笔记--访问者(Visitor)模式 @(设计模式)[设计模式, 访问者模式, visitor] 设计模式学习笔记访问者Visitor模式 基本介绍 访问者案例 类图 实现代码 Visit ...
- 设计模式 - Visitor 模式(访问者模式)
作用:表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. UML结构图: 解析: Visitor模式把对结点的访问封装成一个抽象基类,通过派生 ...
- Visitor模式学习
意图: 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 似乎理解很麻烦,其实说白了,就是动态的给已经写好的代码(类)加入新的功能! 当然,首 ...
- 设计模型之Visitor模式-图书馆管理系统应用C++实现
今天看到<<软件设计师>>面向对象第七章讲到几种设计模式,其中一种为Visitor模式.这种设计模式通过访问者对象的建立,在访问过程中将访问者作为参数传到被访问对象的函数中,实 ...
- visitor 模式
考虑一下设计一个可以包含长方形.正方形.圆形以及文字的视图类.因为视图中每种元素的显示方式都不一样,所以我们很容易做出如下的设计: 在这里,我使用了COMPOSITE模式.对于COMPOSITE模式, ...
- Visitor模式与Acyclic Visitor
visitor模式最基本的是访问者和被访问者.它的优势是不用改变被访问类的任何结构就可以对被访问者施加新的操作,前提是增加一个访问者的子类.其实就是用增加访问者子类的方法替代被访问者方法的增加. 用你 ...
- visitor模式本质
http://topic.csdn.net/t/20051231/14/4492965.html visitor模式的本质是在不修改类结构的前提下为类及所有派生类添加一个"虚函数" ...
最新文章
- 通信行业还是一个靠人际的行业
- MySQL 错误对照表
- 关于主机的思维导图_几张思维导图,让你清楚的知道ip地址怎么回事?
- hdu 1800 Flying to the Mars
- 用自动阈值话处理SVM棋盘
- 微服务架构--链路追踪(Nginx篇)
- AbsListView.LayoutParams
- java中显示动态信息的方法_java里的动态表单技术
- VBA 脚本快速copyExcel单元格的格式
- CV新赛事|常见天气分类
- 宝塔面板 php关闭拓展,宝塔Linux面板中PHP如何安装扩展及禁用函数?
- cordova android ios
- hadoop原理示意图
- 传统密码学(三)——转轮密码机
- 骨传导原理是什么,骨传导耳机对耳朵有伤害吗?
- Database connections will be migrated
- 【python脚本系列】gif录制png序列帧
- 【前端面筋】终于等到你!!!
- sap成本流怎么看_[原创]SAP方丈-写给新手的SAP成本核算流程
- Ansible学习笔记——vault加密
热门文章
- 数字化波形声音的wav文件浅析
- qt 图片适应窗口_Qt图片自适应窗口控件大小
- 优秀的项目经理是如何进行项目管理的
- English digest
- insmod 加载模块过程、modprobe 与 insmod的区别 、lsmod命令
- 推荐算法(一)——FM因式分解机
- 什么是SpringMVC?SpringMVC之hello.jsp实现过程 问题:SpringMVC在JSP页面取不到ModelAndView中的值(已解决)
- Excel从身份证号提取生日
- 从概率上分析“穷不过三代,富不过三代”,且富三代难于穷三代
- python高分书籍推荐_如果只推荐一本 Python 书,我要 Pick 它!