一、概述

  概念

  

  作用于某个对象群中各个对象的操作。它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作。

  引入

  试想这样一个场景,在一个Collection中放入了一大堆的各种对象的引用,取出时却需要根据这些对象的不同具体类型执行不同操作,那我们有如下方案:

  public void show(Collection c) {
Iterator it = c.iterator();
while (it.hasNext()) {
Object o = it.next();
if (o instanceof Integer) {
// Integer对应的操作
} else if (o instanceof String) {
// String对应的操作
} else if (o instanceof Collection) {
// Collection对应的操作
} else {
// 省略若干个else if
}
}
}

  就不分析说这段代码到底有什么问题了,我们直接引入解决办法:访问者模式——把数据结构和数据结构之上的操作解耦

  UML简图

  

  结构

  

  角色

  抽象访问者:声明多个访问操作

  具体访问者:实现接口中操作

  抽象节点:声明接受操作,接收访问者作为一个参量

  具体节点:实现接受操作

  结构对象:可以遍历结构中所有元素

二、实践

  根据角色给出示意性代码:

  抽象访问者

/**
* 访问者接口
*
* @author Administrator
**/
public interface Visitor {
/**
* 访问NodeA
* @param node 访问结点
*/
void visit(NodeA node); /**
* 访问NodeB
* @param node 访问结点
*/
void visit(NodeB node);
}

  具体访问者

/**
* 访问者A
*
* @author Administrator ON 2017/11/3
**/
public class VisitorA implements Visitor{
@Override
public void visit(NodeA nodeA) {
System.out.println(nodeA.operationA());
} @Override
public void visit(NodeB nodeB) {
System.out.println(nodeB.operationB());
}
}
/**
* 访问者B
*
* @author Administrator ON 2017/11/3
**/
public class VisitorB implements Visitor{
@Override
public void visit(NodeA nodeA) {
System.out.println(nodeA.operationA());
} @Override
public void visit(NodeB nodeB) {
System.out.println(nodeB.operationB());
}
}

  抽象结点

/**
* 抽象节点
*
* @author Administrator ON 2017/11/3
**/
public abstract class Node {
public abstract void accept(Visitor v);
}

  具体结点

/**
* A结点
*
* @author Administrator ON 2017/11/3
**/
public class NodeA extends Node{
@Override
public void accept(Visitor v) {
v.visit(this);
}
public String operationA() {
return "A结点特有方法";
}
}
/**
* B结点
*
* @author Administrator ON 2017/11/3
**/
public class NodeB extends Node{
@Override
public void accept(Visitor v) {
v.visit(this);
}
public String operationB() {
return "B结点特有方法";
}
}

  结构对象

/**
* 结构对象
*
* @author Administrator ON 2017/11/3
**/
public class ObjectStructure {
private List<Node> nodeList;
private Node node; public ObjectStructure() {
nodeList = new ArrayList<>();
} /**
* 执行访问操作
*/
public void action(Visitor v) {
Iterator<Node> iterator = nodeList.iterator();
while (iterator.hasNext()) {
node = iterator.next();
node.accept(v);
}
} /**
* 增加一个新结点
* @param node 待增加的结点
*/
public void add(Node node) {
nodeList.add(node);
}
}

  客户端简单操作:

 public static void main(String[] args) {
// 新建并初始化结构对象
ObjectStructure os = new ObjectStructure();
os.add(new NodeA());
os.add(new NodeB());
// 新增访问者并访问
Visitor v1 = new VisitorA();
os.action(v1);
}

  

  我们根据访问者的核心,把上面提出的问题使用访问者模式进行改进

  访问者接口——通过重载实现了不同类型的不同访问

/**
* 集合访问者接口
*
* @author Administrator
**/
public interface CollectionVisitor {
/**
* 访问String元素
* @param se String类型元素
*/
void visit(StringElement se); /**
* 访问Integer类型元素
* @param ie Integer类型元素
*/
void visit(IntegerElement ie);
}

  具体访问者

/**
* 具体访问者
*
* @author Administrator ON 2017/11/3
**/
public class ConcreteVisitor implements CollectionVisitor{
@Override
public void visit(StringElement se) {
System.out.println(se.stringValue());
} @Override
public void visit(IntegerElement ie) {
System.out.println(ie.integerValue());
}
}

  抽象被访问元素——通过accept接收访问者

/**
* 元素接口
*
* @author Administrator ON 2017/11/3
**/
public interface Element {
/**
* 接收访问
* @param visitor 访问者
*/
void accept(CollectionVisitor visitor);
}

  具体元素

/**
* String类型的元素
*
* @author Administrator ON 2017/11/3
**/
public class StringElement implements Element{
@Override
public void accept(CollectionVisitor visitor) {
visitor.visit(this);
}
public String stringValue() {
return "StringElement";
}
}
/**
* Integer类型元素
*
* @author Administrator ON 2017/11/3
**/
public class IntegerElement implements Element{
@Override
public void accept(CollectionVisitor visitor) {
visitor.visit(this);
}
public Integer integerValue() {
return 1;
}
}

  客户端使用

/**
* 客户端
* @author Administrator
**/
public class Client { public static void main(String[] args) {
// 创建需要访问的元素对象集合
List<Element> elementList = new ArrayList<>();
elementList.add(new StringElement());
elementList.add(new IntegerElement());
// 创建访问者
CollectionVisitor visitor = new ConcreteVisitor();
// 接收访问者开始访问
for (Element element : elementList) {
element.accept(visitor);
}
}
}

三、改进与思考

  应当指明,只有在系统十分稳定,确定不会加入新结点时使用,因为加入新节点将无法做到“开闭原则”

  特别注意,访问者模式是解决了不停判断的问题!可以直接根据传入的参数进行判断和接收(回传球)

  浅显的栗子请参见:http://ifeve.com/visitor-design-pattern-in-java-example-tutorial/

Java设计模式(23)——行为模式之访问者模式(Visitor)的更多相关文章

  1. Java 设计模式系列(二三)访问者模式(Vistor)

    Java 设计模式系列(二三)访问者模式(Vistor) 访问者模式是对象的行为模式.访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以 ...

  2. 设计模式之第20章-访问者模式(Java实现)

    设计模式之第20章-访问者模式(Java实现) “嘿,你脸好红啊.”“精神焕发.”“怎么又黄了?”“怕冷,涂的,涂的,蜡.”“身上还有酒味,露馅了吧,原来是喝酒喝的啊.”“嘿嘿,让,让你发现了,今天来 ...

  3. Java设计模式之十一种行为型模式(附实例和详解)

    Java经典设计模式共有21中,分为三大类:创建型模式(5种).结构型模式(7种)和行为型模式(11种). 本文主要讲行为型模式,创建型模式和结构型模式可以看博主的另外两篇文章:J设计模式之五大创建型 ...

  4. 设计模式学习-使用go实现访问者模式

    访问者模式 定义 优点 缺点 适用范围 代码实现 什么是 Double Dispatch 参考 访问者模式 定义 访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作.它使你可以在不 ...

  5. Java设计模式(三) 抽象工厂模式

    原创文章,同步发自作者个人博客,转载请注明出处 http://www.jasongj.com/design_pattern/abstract_factory/ 抽象工厂模式解决的问题 上文<工厂 ...

  6. Java设计模式(十二) 策略模式

    原创文章,同步发自作者个人博客,http://www.jasongj.com/design_pattern/strategy/ 策略模式介绍 策略模式定义 策略模式(Strategy Pattern) ...

  7. Java设计模式(二) 工厂方法模式

    本文介绍了工厂方法模式的概念,优缺点,实现方式,UML类图,并介绍了工厂方法(未)遵循的OOP原则 原创文章.同步自作者个人博客 http://www.jasongj.com/design_patte ...

  8. Java设计模式(一) 简单工厂模式不简单

    摘要:本文介绍了简单工厂模式的概念,优缺点,实现方式,以及结合Annotation和反射的改良方案(让简单工厂模式不简单).同时介绍了简单工厂模式(未)遵循的OOP原则.最后给出了简单工厂模式在JDB ...

  9. Java设计模式(十一) 享元模式

    原创文章,同步发自作者个人博客 http://www.jasongj.com/design_pattern/flyweight/.转载请注明出处 享元模式介绍 享元模式适用场景 面向对象技术可以很好的 ...

  10. Java设计模式(14)责任链模式(Chain of Responsibility模式)

    Chain of Responsibility定义:Chain of Responsibility(CoR) 是用一系列类(classes)试图处理一个请求request,这些类之间是一个松散的耦合, ...

随机推荐

  1. 关于项目中的DAL数据接入层架构设计

    摘要:项目中对关系型数据库的接入再寻常不过,也有海量的ORM工具可供选择,一个一般性的DAL数据接入层的结构却大同小异,这里就分享一下使用Hibernate.Spring.Hessian这三大工具对D ...

  2. Allocate exception for servlet ValidateUsernameServlet 异常

    如果eclipse无法对类文件进行编译那么运行时就会发生 Allocate exception for servlet ValidateUsernameServlet 异常,说找不到类.

  3. 关于PHP数组你应该知道的事情

    (1).PHP数组的遍历顺序 先举个栗子: <?php $arr['a'] = '123'; $arr['b'] = '456'; $arr['c'] = '789'; foreach($a a ...

  4. Linux网络配置&进程管理

     原理图 查看ip和网关

  5. Linux tmux 使用指南

    注意:本文内容适用于 Tmux 2.3 及以上的版本,但是绝大部分的特性低版本也都适用,鼠标支持.VI 模式.插件管理在低版本可能会与本文不兼容. Tmux 快捷键 & 速查表 启动新会话: ...

  6. UDP and TCP

    UDP unreliable, just add de-multiplexing and error checking on data than IP. Best effort datagram(数据 ...

  7. love paradise - 陈慧琳

    love paradise - 陈慧琳 You're always on my mind All day just all the time You're everything to me Brigh ...

  8. UIScrollView的常用属性

    UIScrollView的常用属性

  9. flask模板语言,装饰器,路由及配置

    1.模板语言jinja2 Flask中默认的模板语言是Jinja2 1.0 模板传参 from flask import Flask,render_template app = Flask(__nam ...

  10. java中强引用、软引用、弱引用、幻象引用有什么区别?分别使用在什么场景?

    不同的引用类型,主要体现在对象的不同可达性(reachable)状态和对垃圾收集的影响. 1.强引用是我们最常见的普通对象引用,只要还有强引用指向一个对象,就表明对象还"活着",垃 ...