訪问者模式(Visitor Pattern)是GoF提出的23种设计模式中的一种,属于行为模式。

据《大话设计模式》中说算是最复杂也是最难以理解的一种模式了。

定义(源于GoF《Design Pattern》):表示一个作用于某对象结构中的各元素的操作。它使你能够在
不改变各元素类的前提下定义作用于这些元素的新操作。从定义能够看出结构对象是使用訪问者模式必备
条件,并且这个结构对象必须存在遍历自身各个对象的方法。这便类似于Java语言其中的collection概念了。
涉及角色 :
1.IVisitor 抽象訪问者角色,为该对象结构中详细元素角色声明一个訪问操作接口。该操作接口的名字和
參数标识了发送訪问请求给具休訪问者的具休元素角色,这样訪问者就能够通过该元素角色的特定接口直接訪问它。
2.ConcreteVisitor.详细訪问者角色,实现Visitor声明的接口。
3.Element 定义一个接受訪问操作(accept()),它以一个訪问者(Visitor)作为參数。
4.ConcreteElement 详细元素,实现了抽象元素(Element)所定义的接受操作接口。
5.ObjectStructure 结构对象角色,这是使用訪问者模式必备的角色。

它具备下面特性:

能枚举它的元素;能够提供一个高层接口以同意訪问者訪问它的元素;如有须要,能够设计成一个
复合对象或者一个聚集(如一个列表或无序集合)。
訪问者模式的几个特点:
訪问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。
訪问者模式适用于数据结构相对稳定算法又易变化的系统。

由于訪问者模式使得算法操作添加变得easy。

若系统数据结构对象易于变化。常常有新的数据对象添加进来,则不适合使用訪问者模式。
訪问者模式的长处是添加操作非常easy,由于添加操作意味着添加新的訪问者。

訪问者模式将有关行为集中

到一个訪问者对象中,其改变不影响系统数据结构。其缺点就是添加新的数据结构非常困难。
适用情况 :
1) 一个对象结构包括非常多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其详细类的操作。
2) 须要对一个对象结构中的对象进行非常多不同的而且不相关的操作。而你想避免让这些操作“污染”这些对象的类。
Visitor模式使得你能够将相关的操作集中起来 定义在一个类中。
3) 当该对象结构被非常多应用共享时。用Visitor模式让每一个应用仅包括须要用到的操作。
4) 定义对象结构的类非常少改变,但常常须要在此结构上定义新的操作。

改变对象结构类须要重定义对全部訪

问者的接口,这可能须要非常大的代价。

假设对象结构类常常改变,那么可能还是在这些类中定义这些操作较好。

public class Body {  
public void accept(IVisitor visitor) {  
visitor.visit(this);  
}  
}  
public class Engine {  
public  void accept(IVisitor visitor) {  
visitor.visit(this);  
}  
}  
public class Wheel {  
private String name;  
public Wheel(String name) {  
this.name = name;  
}  
String getName() {  
return this.name;  
}  
public  void accept(IVisitor visitor) {  
visitor.visit(this);  
}  
}  
public class Car {  
private Engine  engine = new Engine();  
private Body    body   = new Body();  
private Wheel[] wheels   
= { new Wheel("front left"), new Wheel("front right"),  
new Wheel("back left") , new Wheel("back right")  };  
public void accept(IVisitor visitor) {  
visitor.visit(this);  
engine.accept(visitor);  
body.accept(visitor) ;   
for (int i = 0; i < wheels.length; ++ i)  
wheels[i].accept(visitor);  
}  
}    
public interface IVisitor {  
void visit(Wheel wheel);  
void visit(Engine engine);  
void visit(Body body);  
void visit(Car car);  
}    
public class PrintVisitor implements IVisitor {   
@Override  
public void visit(Wheel wheel) {  
System.out.println("Visiting " + wheel.getName() + " wheel");   
}    
@Override  
public void visit(Engine engine) {  
System.out.println("Visiting engine");  
}    
@Override  
public void visit(Body body) {  
System.out.println("Visiting body");  
}    
@Override  
public void visit(Car car) {  
System.out.println("Visiting car");  
}   

}

------------------------样例2-----------------------

Visitor模式,在不改动已有程序结构的前提下,通过加入额外的“訪问者”来完毕对已有代码功能的提升。Visitor模式的组成结构:

  1) 訪问者角色(Visitor):声明一个訪问接口。

接口的名称和方法的參数标识了向訪问者发送请求的元素角色。这样訪问者就能够通过该元素角色的特定接口直接訪问它。

  2) 详细訪问者角色(Concrete Visitor):实现訪问者角色(Visitor)接口
  3) 元素角色(Element):定义一个Accept操作,它以一个訪问者为參数。
  4) 详细元素角色(Concrete Element):实现元素角色(Element)接口。
  5) 对象结构角色(Object Structure):这是使用Visitor模式必须的角色。它要具备下面特征:能枚举它的元素;能够提供一个高层的接口同意訪问者角色訪问它的元素;能够是一个组合(组合模式)或是一个集合,如一个列表或一个无序集合
public abstract class Customer {
private String customerId;
private String name;
public String getCustomerId() {
return customerId;
}
public void setCustomerId(String customerId) {
this.customerId = customerId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//接受訪问者的訪问
public abstract void accept(Visitor visitor);
//企业客户
public class EnterpriseCustomer extends Customer {
private String linkman;
private String linkTelephone;
private String registerAddress;
public String getLinkman() {
return linkman;
}
public void setLinkman(String linkman) {
this.linkman = linkman;
}
public String getLinkTelephone() {
return linkTelephone;
}
public void setLinkTelephone(String linkTelephone) {
this.linkTelephone = linkTelephone;
}
public String getRegisterAddress() {
return registerAddress;
}
public void setRegisterAddress(String registerAddress) {
this.registerAddress = registerAddress;
}
@Override
public void accept(Visitor visitor) {
//回调訪问者对象的方法
visitor.visitEnterpriseCustomer(this);
}
}
//个人客户
public class PersonalCustomer extends Customer {
private String telephone;
private int age;
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public void accept(Visitor visitor) {
//回调訪问者对象的方法
visitor.visitPersonalCustomer(this);
}
}
/**
* 訪问者接口
*/
public interface Visitor {
// 訪问企业客户。相当于给企业客户加入訪问者功能
public void visitEnterpriseCustomer(EnterpriseCustomer ec);
//訪问个人客户,相当于给个人客户加入訪问者的功能
public void visitPersonalCustomer(PersonalCustomer pc);
}
/**
* 详细的訪问者。实现对客户的偏好分析
*/
public class PredilectionAnalyzeVisitor implements Visitor {
@Override
public void visitEnterpriseCustomer(EnterpriseCustomer ec) {
// TODO 依据以往的购买历史、潜在购买意向,以及客户所在行业的发展趋势、客户的发展趋势等的分析
System.out.println("如今对企业客户" + ec.getName() + "进行产品偏好分析");
}
@Override
public void visitPersonalCustomer(PersonalCustomer pc) {
System.out.println("如今对个人客户" + pc.getName() + "进行产品偏好分析");
}
}
/**
* 详细的訪问者,实现客户提出服务请求的功能
*/
public class ServiceRequestVisitor implements Visitor {
@Override
public void visitEnterpriseCustomer(EnterpriseCustomer ec) {
// TODO 企业客户提出的详细服务请求
System.out.println(ec.getName() + "企业提出服务请求");
}
@Override
public void visitPersonalCustomer(PersonalCustomer pc) {
// TODO 个人客户提出的详细服务请求
System.out.println("客户" + pc.getName() + "提出服务请求");
}
}
public class ObjectStructure {
/**
* 要操作的客户集合
*/
private Collection<Customer> col = new ArrayList<Customer>();
/**
* 提供client操作的高层接口,详细的功能由client传入的訪问者决定
* @param visitor client须要的訪问者
*/
public void handleRequest(Visitor visitor) {
for(Customer cm : col) {
cm.accept(visitor);
}
}
/**
* 组建对象结构,想对象中加入元素
* 不同的对象结构有不同的构建方式
* @param ele 增加到对象的结构元素
*/
public void addElement(Customer ele) {
this.col.add(ele);
}
}
public class Client {
public static void main(String[] args) {
ObjectStructure os = new ObjectStructure();
Customer cml = new EnterpriseCustomer();
cml.setName("钢铁侠");
os.addElement(cml);
Customer cm2 = new EnterpriseCustomer();
cm2.setName("CDE公司");
os.addElement(cm2);
Customer cm3 = new PersonalCustomer();
cm3.setName("美国佬");
os.addElement(cm3);
ServiceRequestVisitor srVisitor = new ServiceRequestVisitor();
os.handleRequest(srVisitor);
PredilectionAnalyzeVisitor paVisitor = new PredilectionAnalyzeVisitor();
os.handleRequest(paVisitor);
WorthAnalyzeVisitor waVisitor = new WorthAnalyzeVisitor();
os.handleRequest(waVisitor);
}
}

设计模式之十五:訪问者模式(Visitor Pattern)相关推荐

  1. 【每天一个java设计模式(十五)】 - 命令模式

    命令模式是一种数据驱动的设计模式,它属于行为型模式.请求以命令的形式包裹在对象中,并传给调用对象.调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令. 命令模式也就是一个 ...

  2. 设计模式(十五)享元模式(结构型)

    概述 当一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等问题.例如在一个文本字符串中存在很多重复的字符,如果每一个字符都用一个单独的对象来表示,将会占用较多的内存空间,那 ...

  3. 设计模式(十五):解释器模式

    一.定义 在设定环境中,定义一种规则或者语法,通过解释器来解释规则或者语法的含义. 二.实例:将  二十一    ->    21 2.1 设定我们的环境 Context public clas ...

  4. 【每天一个java设计模式(十四)】 - 解释器模式

    解释器模式提供了评估语言的语法或表达式的方式,它属于行为型模式.这种模式实现了一个表达式接口,该接口解释一个特定的上下文. 解释器模式主要包括以下几个部分: 抽象表达式角色:定义解释器的接口,约定解释 ...

  5. 享元模式 FlyWeight 结构型 设计模式(十五)

    享元模式(FlyWeight)  "享"取"共享"之意,"元"取"单元"之意. 意图 运用共享技术,有效的支持大量细粒度 ...

  6. 云计算设计模式(十五)——管道和过滤器模式

    云计算设计模式(十五)--管道和过滤器模式 分解,执行复杂处理成一系列可重复使用分立元件的一个任务.这种模式可以允许执行的处理进行部署和独立缩放任务元素提高性能,可扩展性和可重用性. 背景和问题 一个 ...

  7. 3.5 訪问者模式(5.11)

    訪问者模式的学习.能够从以下方面入手. 假设一门编程语言支持双分派(多分派).那么訪问者模式就没有太大的存在价值.其实,看完Java模拟 双分派Double Dispatch,你应该自己做最后的题目: ...

  8. 设计模式(十四)中介者模式

    相关文章 设计模式(一)设计六大原则 设计模式(二)单例模式的七种写法 设计模式(三)建造者模式 设计模式(四)简单工厂模式 设计模式(五)观察者模式 设计模式(六)代理模式 设计模式(七)装饰模式 ...

  9. 45.深度解密四十五:网站盈利模式和私域流量的变现方式细致讲解

    网络营销推广技术.技巧深度解密(四十五)指南: 1.本文档适合零基础以及互联网营销推广工作者,主要讲解网站的盈利模式和私域流量变现的方式问题. 2.原创版权文档,任何抄袭或者全部.部分模仿都是侵权行为 ...

最新文章

  1. 【C#】Out与ref是干什么的?
  2. 简单的 HTTP 调用,为什么时延这么大?
  3. apt-get常用命令及工作原理
  4. 开源开放 | 《大词林》开源 75 万核心实体和围绕核心实体的细粒度概念、关系列表...
  5. php laravel 优点,Laravel 特点有哪些?
  6. Java中的Map、Set、List各种方式遍历
  7. (转)淘淘商城系列——使用maven tomcat插件启动web工程
  8. 用计算机弹雅俗共赏,聊聊雅俗共赏:钢琴、饺子和面
  9. 双边滤波器和高斯滤波器
  10. AVI视频文件损坏修复
  11. 禁用 Word 2013/2016 信息检索
  12. Pytorch中BatchNorm中running_mean和running_var的计算方法
  13. Java 方法与C语言函数微区别
  14. 常用英语口语绝佳句型100句
  15. python外星人入侵游戏加随机游动_Python外星人入侵游戏(四):飞船左右移动
  16. ESP8266-Arduino编程实例-L9110直流电机风扇传感器模块
  17. 51CTO学习笔记--Linux运维故障排查思路与系统调优技巧视频课程(高俊峰)
  18. VBA Project密码解除
  19. 洛谷-2324-骑士精神
  20. 用计算机弹出画的伴奏,《体面》钢琴伴奏_关于建立声乐作品计算机音乐伴奏曲库的一些思考...

热门文章

  1. java方法的重载 编程题,java面试编程题:重载方法
  2. 使用了未初始化的局部变量_Java 成员变量和局部变量
  3. 网络安全模型_工业互联网态势感知,看得见的网络安全
  4. asp.net mvc4 mysql_ASP.NET MVC4 with MySQL: Configuration Error (MySql.Web.v20)
  5. HTTPS是对称加密还是非对称加密?
  6. java 组合 遍历 算法_java编程n个集合每次从每个集合里面取出一个元素组成一个字符串列出所有组合算法...
  7. Vue父组件访问子组件属性和方法、父子组件双向绑定(两种方法)
  8. 计算机做减法运算的过程,32位汇编基础_计算机做加减乘除
  9. 不能使用zsh或myzsh创建/切换 包含#的分支名(zsh: bad pattern: #xxx)
  10. 如何linux网页修改回80端口,linux下如何修改iptables开启80端口