- 浏览: 327468 次
- 性别:
- 来自: 广州
文章分类
最新评论
访问者模式的目的是封装一些施加于某种数据结构元素之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变.
一:访问者模式需要解决的问题
聚集是大多数的系统都要处理的一种容器对象,它保存了对其他对象的引用。相信大多数读者都有处理聚集的经验,但是大家处理过的大多数聚集恐怕都是同类对象的聚集。换言之,在聚集上采取的操作都是一些针对同类型对象的同类操作,而迭代子就是为这种情况准备的设计模式.下面看一个例子:
那么很多人没有考虑过的问题就是,如何针对一个保存有不同类型的对象的聚集采取某种操作呢?仍以上面的print方法为例子,如果collection聚集中的元素有可能还是聚集,那么调用聚集的toString就没有意义了,应该调用它的内部元素的toString方法,换言之,上面的方法应该改写为:
这个条件转移语句变得越来越长,代码也越来越难以维护。换言之,如果需要针对一个包含不同类型的聚集采取某种操作时,而操作的细节根据元素的类型不同而有所不同时,就会出现必须对元素类型做类型判断的条件转移语句(这实际上就是双重分派的实际应用).
这个问题我们就可以用访问者模式来解决.
二:访问者模式
访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于数据结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化.数据结构的每一个节点都可以接受一个访问者的调用,此节点向访问者对象传入节点对象,而访问者对象则反过来执行节点对象的操作,这样的过程叫做双重要分派.节点调用访问者,将它自己的传入,访问者则将某算法针对此节点执行.它所涉及的角色如下:
(A)抽象访问者(Visitor)角色:声明了一个或者多个访问操作,形成所有的具体元素角色必须实现的接口,它为每一个具体节点都准备了一个访问操作.
(B)具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口.
(C)抽象节点(Node)角色:声明一个接受操作,接受一个访问者对象作为一个参量
(D)具体节点(ConcreteNode)角色:实现了抽象元素所规定的接受操作
(E)结构对象(ObjectStructure)角色:可以遍历结构中的所有元素,如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素,如果需要,可以设计成一个复合对象或者一个聚集如List。
下面看示意源码:
三:在什么情况下使用访问者模式
有意思的是,在很多情况下不使用设计模式反而会得到一个较好的设计,换言之,每一个设计模式都有其不应当使用的情况.访问者模式仅仅应当在被访问的类结构非常稳定的情况下使用,换言之系统很少出现需要加入新节点的情况.
如果需要加入新节点的情况,那就必须在每一个访问对象里加入一个对应于这个新节点的访问操作,而这是对一个系统的大规模修改,这违背了"开闭原则".总之,如果系统的数据结构是频繁变化的,则不适用访问者模式.它的优点有:
(a)使得增加新的操作变得容易
(b)访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个节点类中.
一:访问者模式需要解决的问题
聚集是大多数的系统都要处理的一种容器对象,它保存了对其他对象的引用。相信大多数读者都有处理聚集的经验,但是大家处理过的大多数聚集恐怕都是同类对象的聚集。换言之,在聚集上采取的操作都是一些针对同类型对象的同类操作,而迭代子就是为这种情况准备的设计模式.下面看一个例子:
public void print(Collection collection){ Iterator iterator = (Iterator) collection.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next().toString()); } }
那么很多人没有考虑过的问题就是,如何针对一个保存有不同类型的对象的聚集采取某种操作呢?仍以上面的print方法为例子,如果collection聚集中的元素有可能还是聚集,那么调用聚集的toString就没有意义了,应该调用它的内部元素的toString方法,换言之,上面的方法应该改写为:
public void print(Collection collection){ Iterator iterator = (Iterator) collection.iterator(); while(iterator.hasNext()){ Object o = iterator.next(); if(o instanceof Collection){ print((Collection)o); }else{ System.out.println(iterator.next().toString()); } } } 但是这还没完,如果这个操作对不同的类型的元素有所不同时怎么办?比如系统要求打印字符串时加上单引号,打印Double类型的数据时,在数据后面加上D,在打印Float类型的数据时,在数据后面加上F,这时我们还继续修改print方法: public void print(Collection collection){ Iterator iterator = (Iterator) collection.iterator(); while(iterator.hasNext()){ Object o = iterator.next(); if(o instanceof Collection){ print((Collection)o); }else if(o instanceof String){ System.out.println("'" o.toString() "'"); }else if(o instanceof Double){ System.out.println(o.toString() "D"); }else{ System.out.println(iterator.next().toString()); } } }
这个条件转移语句变得越来越长,代码也越来越难以维护。换言之,如果需要针对一个包含不同类型的聚集采取某种操作时,而操作的细节根据元素的类型不同而有所不同时,就会出现必须对元素类型做类型判断的条件转移语句(这实际上就是双重分派的实际应用).
这个问题我们就可以用访问者模式来解决.
二:访问者模式
访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于数据结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化.数据结构的每一个节点都可以接受一个访问者的调用,此节点向访问者对象传入节点对象,而访问者对象则反过来执行节点对象的操作,这样的过程叫做双重要分派.节点调用访问者,将它自己的传入,访问者则将某算法针对此节点执行.它所涉及的角色如下:
(A)抽象访问者(Visitor)角色:声明了一个或者多个访问操作,形成所有的具体元素角色必须实现的接口,它为每一个具体节点都准备了一个访问操作.
(B)具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口.
(C)抽象节点(Node)角色:声明一个接受操作,接受一个访问者对象作为一个参量
(D)具体节点(ConcreteNode)角色:实现了抽象元素所规定的接受操作
(E)结构对象(ObjectStructure)角色:可以遍历结构中的所有元素,如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素,如果需要,可以设计成一个复合对象或者一个聚集如List。
下面看示意源码:
package cai.milenfan.basic.test; public interface Visitor { //对应NodeA的操作 void visit(NodeA node); //对应NodeB的操作 void visit(NodeB node); }
package cai.milenfan.basic.test; public class VisitorA implements Visitor{ public void visit(NodeA nodeA) { System.out.println(nodeA.operationA()); } public void visit(NodeB nodeB) { System.out.println(nodeB.operationB()); } }
package cai.milenfan.basic.test; public class VisitorB { public void visit(NodeA nodeA) { System.out.println(nodeA.operationA()); } public void visit(NodeB nodeB) { System.out.println(nodeB.operationB()); } }
package cai.milenfan.basic.test; //抽象节点 public abstract class Node { public abstract void accept(Visitor visitor); }
package cai.milenfan.basic.test; public class NodeA extends Node { public void accept(Visitor visitor) { visitor.visit(this); } public String operationA() { return "NodeA is visited"; } }
package cai.milenfan.basic.test; public class NodeB extends Node { public void accept(Visitor visitor) { visitor.visit(this); } public String operationB() { return "NodeB is visited"; } }
package cai.milenfan.basic.test; import java.util.Enumeration; import java.util.Vector; public class ObjectStructure { private Vector nodes; private Node node; public ObjectStructure() { nodes = new Vector(); } public void action(Visitor visitor) { for (Enumeration e = nodes.elements(); e.hasMoreElements();) { node = (Node) e.nextElement(); node.accept(visitor); } } public void add(Node node) { nodes.addElement(node); } }
package cai.milenfan.basic.test; import java.awt.Canvas; public class Client { private static ObjectStructure aObjects; private static Visitor visitor; static public void main(String[] args) { //创建一个结构对象 aObjects = new ObjectStructure(); //给结构增加两个节点 aObjects.add(new NodeA()); aObjects.add(new NodeB()); //创建一个新的访问者 visitor = new VisitorA(); //让访问者访问结构 aObjects.action(visitor); } }
三:在什么情况下使用访问者模式
有意思的是,在很多情况下不使用设计模式反而会得到一个较好的设计,换言之,每一个设计模式都有其不应当使用的情况.访问者模式仅仅应当在被访问的类结构非常稳定的情况下使用,换言之系统很少出现需要加入新节点的情况.
如果需要加入新节点的情况,那就必须在每一个访问对象里加入一个对应于这个新节点的访问操作,而这是对一个系统的大规模修改,这违背了"开闭原则".总之,如果系统的数据结构是频繁变化的,则不适用访问者模式.它的优点有:
(a)使得增加新的操作变得容易
(b)访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个节点类中.
发表评论
-
Mina重连
2014-05-26 21:29 2864import com.sun.swing.internal. ... -
面试经典
2014-05-24 09:29 6061.mysql innodb引擎,什么叫聚集索引,与非聚集索 ... -
一拍网网站系统架构图
2014-03-28 21:24 532一拍网网站系统架构图 -
Window下安装配置nginx
2013-08-12 16:53 733安装:http://www.cnblogs.com/wen ... -
使用线程池的好处
2013-07-18 14:41 1136使用线程池有两个好处: 1.可以创建和销毁线程所带来的系统 ... -
Java ThreadLocal使用浅析
2013-07-18 14:36 412ThreadLocal通过在其内部保存变量的副本,并且各个副本 ... -
MyBatis学习之简单增删改查操作、MyBatis存储过程、MyBatis分页、MyBatis一对一、MyBatis一对多
2013-07-05 13:06 1087http://blog.csdn.net/zhangwei ... -
分享一位网友的架构杂谈
2013-05-20 23:16 869不容类型的网站,并发处理不一样,例如针对sns这种类型的网站 ... -
JSP页面静态化
2013-04-08 09:20 803http://www.java-zone.org/644.ht ... -
Java compile to C++
2013-03-19 14:53 464http://code.google.com/a/eclips ... -
几个TCP Socket的通信框架
2013-03-19 12:26 944http://www.oschina.net/p/simple ... -
宝贝鱼
2013-03-18 23:54 633http://code.google.com/p/cshbbr ... -
将Java程序注册成系统服务(NT服务)
2013-03-16 16:14 569http://blog.csdn.net/small____f ... -
Java内存回收机制
2013-03-13 15:47 780http://www.iteye.com/blogs/tag/ ... -
支付宝,百付宝集成
2013-03-13 14:01 897http://help.alipay.com/support/ ... -
SSH+EXTJS项目下载
2013-03-11 23:02 386http://download.csdn.net/tag/Ex ... -
Hibernate中使用Threadlocal创建线程安全的Session
2013-03-04 20:39 489http://blog.sina.com.cn/s/blog_ ... -
Java Socket多线程通信
2012-10-09 09:53 810当Server没接受到一个Client连接请求之后,都把处理流 ... -
Java 多线程的一个例子
2012-10-09 09:48 983目录: 1 synchronized的 ... -
app引擎
2012-07-10 09:39 0http://sae.sina.com.cn/ htt ...
相关推荐
NULL 博文链接:https://364232252.iteye.com/blog/2370872
68丨访问者模式(上):手把手带你还原访问者模式诞生的思维过程1
第二十三讲:访问者模式 第二十四讲:状态模式 第二十五讲:命令模式 第二十六讲:开放-封闭原则 第二十七讲:里氏转换原则 第二十八讲:依赖倒转原则 第二十九讲:迪米特法则 第三十讲:设计模式总结
C#面向对象设计模式纵横谈(24):(行为型模式) Visitor 访问者模式
访问者模式Demo
设计模式C++学习之访问者模式(Visitor)
设计模式 - 访问者模式
ios 平台实现设计模式-访问者模式,以最简单的代码实现访问者模式讲解,主旨在于了解访问者模式,博客:http://blog.sina.com.cn/s/blog_161d504630102wwxe.html
最简单的访问者模式讲解代码,设计模式可看看博客中简介http://blog.sina.com.cn/s/blog_161d504630102wxis.html
访问者模式代码
java设计模式之访问者模式,通过实际例子说明访问者模式原理和适用场景;
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中...这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
建造者模式组合模式访问者模式 abstract class Bulider{ public abstract void BuildPartA() ; public abstract void BuildPartB() ; public abstract Product GetResult() ; }
访问者模式的小例子
ziji nong de 博文链接:https://daybyday.iteye.com/blog/246900
访问者模式,你绝对会用到的模式,值得学习,通俗易懂的实例,原理和运用都说明白了。
访问者模式的第二个例子
设计模式之访问者模式Java版本的实现和UML类图