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,这些类之间是一个松散的耦合, ...
随机推荐
- bep-10翻译
dht协议的目的是解放tracter服务器,将tracter的任务分布式存到各个客户端上(即维护资源文件的下载列表,从哪能下载到请求的文件): dht协议在get_peer请求获得peer信息后,就会 ...
- 在Windows 10上部署Apache PredictionIO开发环境
Windows在初研究人员的探索下,研究出了一套更为精简的环境配置,极大的缩短了开发时间与效率,在此总结以供后来者参阅. 1.部署环境的配置 Windows10 64 home IntelliJ ID ...
- Visual Studio 2017 离线安装
微软最近发布了正式版Visual Studio 2017并公开了其下载方式,不过由于VS2017采用了新的模块化安装方案,所以微软官方并未提供ISO镜像,但是官方提供了如何进行离线下载的方案给需要进行 ...
- 使用combineReducers注意事项
一.从‘redux’包中引入combineReducers方法: import { combineReducers } from 'redux'; 二.针对state的不同属性写不同的reducer, ...
- AsyncTask基础知识
大家都知道,在子线程中是不能更新UI的,必须要采用异步消息处理机制.一般的做法就是在有需要的地方,使用Handler发送消息给主线程,然后在主线程中处理消息更新UI.如果好多子线程都有更新UI的需求, ...
- Django 导出csv文件 中文乱码问题
import csvimport codecsimport datetimefrom django.db import connectionfrom django.contrib.auth.model ...
- Tomcat的webapps目录下的classes文件夹下缺失编译好的.class文件原因及其解决方法
右键,选择BuildPath: 可以编辑Output folder,指定编译后的文件的存放目录,一般是target/classes目录
- Using the @synchronized Directive
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/ThreadSafe ...
- BZOJ1770:[USACO]lights 燈(高斯消元,DFS)
Description 貝希和她的閨密們在她們的牛棚中玩遊戲.但是天不從人願,突然,牛棚的電源跳閘了,所有的燈都被關閉了.貝希是一個很膽小的女生,在伸手不見拇指的無盡的黑暗中,她感到驚恐,痛苦與絕望. ...
- [USACO19JAN]Exercise Route
题目 这题的数据有点水,暴力合并\(set\)好像过了 分析一下这个题的性质,发现我们一条非树边就会形成一个环,而我们要求选择两个非树边,就会形成两个环,要求不走重复的点,就是说我们需要走一个大环,且 ...