`
阅读更多
     做了标题党=。=这一篇并没有介绍关于访问者模式的进阶,先说一下访问者模式的使用情况,这里引用大话设计模式的例子,因为讲得比较精辟。

假设有男人和女人两种元素,要分别打印出他们在不同状态时的不同表现。
用OO的思想把表现(行为)提取出来作为一个抽象方法,代码如下:

用if-else对状态进行判断
Person接口
public interface Person {
      public void action(String state);
}


Man实现类
public class Man implements Person{

	public void action(String state) {
		if(state == "success"){
			System.out.println("当男人成功时,背后多半有一个伟大的女人");
		}
		else if(state == "love"){
			System.out.println("当男人恋爱时,凡事不懂也装懂");
		}
	}   
}


Woman实现类
public class Woman implements Person{

	public void action(String state) {
		if(state == "success"){
			System.out.println("当女人成功时,背后大多有一个不成功的男人");
		}
		else if(state == "love"){
			System.out.println("当女人恋爱时,遇事懂也装不懂");
		}
	}

}


客户端测试代码

public class Client {
     public static void main(String[] args) {
		Person man = new Man();
		Person woman = new Woman();
		man.action("success");
		woman.action("success");
		
		man.action("love");
		woman.action("love");
	}
}


结果显示:
当男人成功时,背后多半有一个伟大的女人
当女人成功时,背后大多有一个不成功的男人
当男人恋爱时,凡事不懂也装懂
当女人恋爱时,遇事懂也装不懂


当需求发生变化时,要增加一种失败状态时,增加男人女人的不同表现,这时就要修改Man类与Woman类的if else,违反了ocp原则(对增加开放-对修改封闭)。而且随着需求的增加,Man类与Woman类的if,else越来越臃肿,需要取消时,又要去修改if,else,既不方便,又容易出错。
这时候访问者模式可以派上用场了。
请看下面经修改后的类图:




使用访问者模式

把状态抽象出来成为一个接口(访问者),不同的状态就作为状态的不同实现类(不同的访问者)。
状态的接口(访问者接口)
public interface Visitor {
      public void visit(Man man);
      public void visit(Woman woman);
}


具体访问者实现类(分别代表不同的状态)
//成功时Man与Woman的不同表现
public class Success implements Visitor{

	public void visit(Man man) {
		System.out.println("当男人成功时,背后多半有一个伟大的女人");
	}

	public void visit(Woman woman) {
		System.out.println("当女人成功时,背后大多有一个不成功的男人");
	}
}


public class Love implements Visitor{

	public void visit(Man man) {
		System.out.println("当男人恋爱时,凡事不懂也装懂");
	}

	public void visit(Woman woman) {
		System.out.println("当女人恋爱时,遇事懂也装不懂");
	}
}


按照类图改造一下人的接口与实现类
public interface Person {
      void accept(Visitor visitor);
}


public class Man implements Person{

	public void accept(Visitor visitor) {
		visitor.visit(this);
	}
}


public class Woman implements Person{

	public void accept(Visitor visitor) {
          visitor.visit(this);
	}
}

这时Man与Woman变得轻盈多了,不再需要写一大段的if,else,只需要按不同的状态,传入不同的访问者,执行访问者的方法就OK了。


为了更好地实现客户类与具体元素的解耦,加入一个ObjectStructure类。有了ObjectStructure能更方便地执行一些任何,其具体细节对于客户端来说是透明的。
import java.util.*;

public class ObjectStructure {
    private List<Person> elements = new ArrayList<Person>();

    public void attach(Person element){
    	elements.add(element);
    }
    
    public void detach(Person element){
    	elements.remove(elements);
    }
    
    //遍历各种具体元素并执行他们的accept方法
    public void display(Visitor visitor){
    	for(Person p:elements){
    		p.accept(visitor);
    	}
    }
}


客户端测试代码:
public class Client {
      public static void main(String[] args) {
		ObjectStructure o = new ObjectStructure();  //依赖于ObjectStructure
		//实例化具体元素
		o.attach(new Man());  
		o.attach(new Woman());
		
		//当成功时不同元素的不同反映
		Visitor success = new Success();           //依赖于抽象的Visitor接口
		o.display(success);
		
		//当恋爱时的不同反映
		Visitor amativeness = new Love();          //依赖于抽象的Visitor接口
		o.display(amativeness);
	}
}


这时客户端只依赖于ObjectStructure类与Visitor接口,实现了高度的解耦,具体Visitor实现类的实例化与具体元素(Man,Woman)的创建可以通过工厂模式甚至配合properties/xml配置文件创建,无需客户端关注。而Man与Gril的创建的代码也可以放在其他地方,客户端无需知道,如可以放到ObjectStructure的构造函数中完成
	public ObjectStructure(){
		attach(new Man());  
		attach(new Woman());
	}

在实例块{ }中完成实例化也可以。这时如果要增加一种状态的不同操作,只需要增加一个具体访问者,无需要修改具体元素类Man与Woman。代码如下,
public class Fail implements Visitor{

	public void visit(Man man) {
		System.out.println("当男人失败时,闷头喝酒,谁也不用劝");
	}

	public void visit(Woman woman) {
		System.out.println("当女人失败时,眼泪汪汪,谁也劝不了");
	}
}


修改一下客户端测试代码就OK:
public class Client {
      public static void main(String[] args) {
		ObjectStructure o = new ObjectStructure();  //依赖于ObjectStructure
		//实例化具体元素
		o.attach(new Man());  
		o.attach(new Woman());
		
		//当成功时不同元素的不同反映
		Visitor success = new Success();           //依赖于抽象的Visitor接口
		o.display(success);
		
		//当恋爱时的不同反映
		Visitor amativeness = new Love();          //依赖于抽象的Visitor接口
		o.display(amativeness);
		
		//当失败时的不同反映
		Visitor fail = new Fail();
		o.display(fail);
	}
}


结果显示:
当男人成功时,背后多半有一个伟大的女人
当女人成功时,背后大多有一个不成功的男人
当男人恋爱时,凡事不懂也装懂
当女人恋爱时,遇事懂也装不懂
当男人失败时,闷头喝酒,谁也不用劝
当女人失败时,眼泪汪汪,谁也劝不了



现在来让我们看看访问者模式的定义与类图:
访问者模式定义:表示一个作用于某个对象结构中的各元素的操作。它使可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

在我看来可以把访问者模式想象成状态模式的或者策略模式的扩展版(说策略模式会更贴切,策略与状态是有区别的),都是实现对象在不同情况下的不同表现,只是状态与策略主要是针对一种对象,而访问者是针对多种对象。





访问者模式的特点:
1)优点:使用了访问者模式以后,对于原来的类层次增加新的操作,仅仅需要实现一个具体访问者角色就可以了,而不必修改整个类层次,使得类层次结构的代码臃肿难以维护。而且这样符合“开闭原则”的要求。而且每个具体的访问者角色都对应于一个相关操作,因此如果一个操作的需求有变,那么仅仅修改一个具体访问者角色,而不用改动整个类层次。

2)访问者模式的双重分派技术
(1)将具体访问者作为参数传递给具体元素角色
(2)进入具体元素角色后,具体元素角色调用者作为参数的具体访问者的visit方法,同时将自己(this)作为参数传递进行。具体访问者再根据参数的不同来执行相应的方法

3)前提:开闭原则”的遵循总是片面的。如果系统中的类层次发生了变化,会对访问者模式产生什么样的影响呢?你必须修改访问者接口和每一个具体访问者。因此4人组曾经提出,访问者模式适用于数据结构相对稳定的系统

4)适用情况:访问者模式的目的是要把处理从数据结构分离出来。很多系统可以按照算法和数据结构分开,如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式是比较合适的,因为访问者模式似得算法操作的增加变得容易。反之,如果这样的系统的数据结构对象易于变化,经常要有新的数据对象增加进来,就不适合使用访问者模式。

5)思考:如何让访问者模式变得更加灵活?
Java的Reflect技术解决了上述问题,因此结合reflect反射机制,可以使得访问者模式适用范围更广了。想了解具体详情,请看下一篇文章访问者模式进阶(二)
  • 大小: 23.7 KB
  • 大小: 24.5 KB
分享到:
评论
2 楼 sanpic 2015-07-22  
  不错
1 楼 zhangleipd 2013-07-09  

相关推荐

    java中级进阶高级23种设计模式详细介绍+代码详解PPT模板.pptx

    访问者模式 java中级进阶高级23种设计模式详细介绍+代码详解PPT模板全文共26页,当前为第23页。 中介者模式 java中级进阶高级23种设计模式详细介绍+代码详解PPT模板全文共26页,当前为第24页。 解释器模式 java中级...

    Java设计模式整理

    java设计模式word整理,付代码说明,时候java进阶选手,欢迎选购! 目录 1 1. 设计模式 2 1.1 创建型模式 2 1.1.1 工厂方法 2 1.1.2 抽象工厂 4 1.1.3 建造者模式 6 1.1.4 单态模式 9 ...1.3.11 访问者模式 43

    GO语言进阶.docx

    9-4_RabbitMQ工作原理和转发模式.mp4 9-5_Docker安装RabbitMQ及UI管理.mp4 9-6_编码实战_实现异步转移的MQ生产者.mp4 9-7_编码实战_实现异步转移的MQ消费者.mp4 9-8_编码实战_异步转移文件测试+小结.mp4 第10章...

    实验12 单例模式与枚举.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

    实验7 成员访问控制与异常.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

    Java实验6多线程.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

    Java实验8 数据库.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

    实验8 javaFX程序设计.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

    实验2 Java语言基础.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

    基于身份认证和多模式的AES保密通信协议C++源码(含项目说明).zip

    1. 该密码学大作业设计了一个高仿真的保密通信协议,全过程模拟真实用户访问状态,可以加密传输任意类型任意大小文件,自主选则 **CBC、CFB**加密模式,采用具有**保密性和认证性**的密钥分配协议,利用 RSA 公钥...

    实验1 Java环境搭建.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

    自己动手写操作系统

    3.2 保护模式进阶50 3.2.1 海阔凭鱼跃50 3.2.2 LDT(Local Descriptor Table)58 3.2.3 特权级62 3.3 页式存储82 3.3.1 分页机制概述83 3.3.2 编写代码启动分页机制84 3.3.3 PDE和PTE85 3.3.4 cr388 3.3.5 ...

    asp.net知识库

    .NET关于string转换的一个小Bug Regular Expressions 完整的在.net后台执行javascript脚本集合 ASP.NET 中的正则表达式 常用的匹配正则表达式和实例 经典正则表达式 delegate vs. event 我是谁?[C#] 表达式计算引擎...

    实验9 Servlet.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

    实验9 Java输入输出流.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

    实验10 JSP.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

    实验11 XML解析.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

    Java实验7 序列化.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

    Java实验2 反射.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

    实验5 网络编程.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员访问控制与异常、JavaFX程序设计、Java...

Global site tag (gtag.js) - Google Analytics