Java设计模式(23)——行为模式之访问者模式(Visitor)
一、概述
概念

作用于某个对象群中各个对象的操作。它可以使你在不改变这些对象本身的情况下,定义作用于这些对象的新操作。
引入
试想这样一个场景,在一个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)的更多相关文章
- Java 设计模式系列(二三)访问者模式(Vistor)
Java 设计模式系列(二三)访问者模式(Vistor) 访问者模式是对象的行为模式.访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以 ...
- 设计模式之第20章-访问者模式(Java实现)
设计模式之第20章-访问者模式(Java实现) “嘿,你脸好红啊.”“精神焕发.”“怎么又黄了?”“怕冷,涂的,涂的,蜡.”“身上还有酒味,露馅了吧,原来是喝酒喝的啊.”“嘿嘿,让,让你发现了,今天来 ...
- Java设计模式之十一种行为型模式(附实例和详解)
Java经典设计模式共有21中,分为三大类:创建型模式(5种).结构型模式(7种)和行为型模式(11种). 本文主要讲行为型模式,创建型模式和结构型模式可以看博主的另外两篇文章:J设计模式之五大创建型 ...
- 设计模式学习-使用go实现访问者模式
访问者模式 定义 优点 缺点 适用范围 代码实现 什么是 Double Dispatch 参考 访问者模式 定义 访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作.它使你可以在不 ...
- Java设计模式(三) 抽象工厂模式
原创文章,同步发自作者个人博客,转载请注明出处 http://www.jasongj.com/design_pattern/abstract_factory/ 抽象工厂模式解决的问题 上文<工厂 ...
- Java设计模式(十二) 策略模式
原创文章,同步发自作者个人博客,http://www.jasongj.com/design_pattern/strategy/ 策略模式介绍 策略模式定义 策略模式(Strategy Pattern) ...
- Java设计模式(二) 工厂方法模式
本文介绍了工厂方法模式的概念,优缺点,实现方式,UML类图,并介绍了工厂方法(未)遵循的OOP原则 原创文章.同步自作者个人博客 http://www.jasongj.com/design_patte ...
- Java设计模式(一) 简单工厂模式不简单
摘要:本文介绍了简单工厂模式的概念,优缺点,实现方式,以及结合Annotation和反射的改良方案(让简单工厂模式不简单).同时介绍了简单工厂模式(未)遵循的OOP原则.最后给出了简单工厂模式在JDB ...
- Java设计模式(十一) 享元模式
原创文章,同步发自作者个人博客 http://www.jasongj.com/design_pattern/flyweight/.转载请注明出处 享元模式介绍 享元模式适用场景 面向对象技术可以很好的 ...
- Java设计模式(14)责任链模式(Chain of Responsibility模式)
Chain of Responsibility定义:Chain of Responsibility(CoR) 是用一系列类(classes)试图处理一个请求request,这些类之间是一个松散的耦合, ...
随机推荐
- 关于项目中的DAL数据接入层架构设计
摘要:项目中对关系型数据库的接入再寻常不过,也有海量的ORM工具可供选择,一个一般性的DAL数据接入层的结构却大同小异,这里就分享一下使用Hibernate.Spring.Hessian这三大工具对D ...
- Allocate exception for servlet ValidateUsernameServlet 异常
如果eclipse无法对类文件进行编译那么运行时就会发生 Allocate exception for servlet ValidateUsernameServlet 异常,说找不到类.
- 关于PHP数组你应该知道的事情
(1).PHP数组的遍历顺序 先举个栗子: <?php $arr['a'] = '123'; $arr['b'] = '456'; $arr['c'] = '789'; foreach($a a ...
- Linux网络配置&进程管理
原理图 查看ip和网关
- Linux tmux 使用指南
注意:本文内容适用于 Tmux 2.3 及以上的版本,但是绝大部分的特性低版本也都适用,鼠标支持.VI 模式.插件管理在低版本可能会与本文不兼容. Tmux 快捷键 & 速查表 启动新会话: ...
- UDP and TCP
UDP unreliable, just add de-multiplexing and error checking on data than IP. Best effort datagram(数据 ...
- love paradise - 陈慧琳
love paradise - 陈慧琳 You're always on my mind All day just all the time You're everything to me Brigh ...
- UIScrollView的常用属性
UIScrollView的常用属性
- flask模板语言,装饰器,路由及配置
1.模板语言jinja2 Flask中默认的模板语言是Jinja2 1.0 模板传参 from flask import Flask,render_template app = Flask(__nam ...
- java中强引用、软引用、弱引用、幻象引用有什么区别?分别使用在什么场景?
不同的引用类型,主要体现在对象的不同可达性(reachable)状态和对垃圾收集的影响. 1.强引用是我们最常见的普通对象引用,只要还有强引用指向一个对象,就表明对象还"活着",垃 ...