设计模式之十八——访问者模式
2019-07-01 本文已影响0人
dd299
1 介绍
访问者模式是对象的行为模式。访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保持不变。
1.1 什么是访问者模式
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
1.2 解决了什么问题
访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。
2 原理
- 访问者模式涉及到的角色如下:
- 抽象访问者(Visitor)角色:声明了一个或者多个方法操作,形成所有的具体访问者角色必须实现的接口。
- 具体访问者(ConcreteVisitor)角色:实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作。
- 抽象节点(Node)角色:声明一个接受操作,接受一个访问者对象作为一个参数。
- 具体节点(ConcreteNode)角色:实现了抽象节点所规定的接受操作。
- 结构对象(ObjectStructure)角色:有如下的责任,可以遍历结构中的所有元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或者一个聚集,如List或Set。
2.1 uml图
- 类图

- 准备过程时序图

- 访问过程时序图

结构对象会遍历它自己所保存的聚集中的所有节点,在本系统中就是节点NodeA和NodeB。首先NodeA会被访问到,这个访问是由以下的操作组成的:
(1)NodeA对象的接受方法accept()被调用,并将VisitorA对象本身传入;
(2)NodeA对象反过来调用VisitorA对象的访问方法,并将NodeA对象本身传入;
(3)VisitorA对象调用NodeA对象的特有方法operationA()。
接着,NodeB会被访问,这个访问的过程和NodeA被访问的过程是一样的。
2.2 代码示例
Visitor代码示例
public interface Visitor {
/**
* 对应于NodeA的访问操作
*/
public void visit(NodeA node);
/**
* 对应于NodeB的访问操作
*/
public void visit(NodeB node);
}
VisitorA代码示例
public class VisitorA implements Visitor {
/**
* 对应于NodeA的访问操作
*/
@Override
public void visit(NodeA node) {
System.out.println(node.operationA());
}
/**
* 对应于NodeB的访问操作
*/
@Override
public void visit(NodeB node) {
System.out.println(node.operationB());
}
}
VisitorB代码示例
public class VisitorB implements Visitor {
/**
* 对应于NodeA的访问操作
*/
@Override
public void visit(NodeA node) {
System.out.println(node.operationA());
}
/**
* 对应于NodeB的访问操作
*/
@Override
public void visit(NodeB node) {
System.out.println(node.operationB());
}
}
Node代码示例
public abstract class Node {
/**
* 接受操作
*/
public abstract void accept(Visitor visitor);
}
NodeA代码示例
public class NodeA extends Node{
/**
* 接受操作
*/
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
/**
* NodeA特有的方法
*/
public String operationA(){
return "NodeA";
}
}
NodeB代码示例
public class NodeB extends Node{
/**
* 接受方法
*/
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
/**
* NodeB特有的方法
*/
public String operationB(){
return "NodeB";
}
}
ObjectStructure代码示例
public class ObjectStructure {
private List<Node> nodes = new ArrayList<Node>();
/**
* 执行方法操作
*/
public void action(Visitor visitor){
for(Node node : nodes)
{
node.accept(visitor);
}
}
/**
* 添加一个新元素
*/
public void add(Node node){
nodes.add(node);
}
}
调用示例
public class Client {
public static void main(String[] args) {
//创建一个结构对象
ObjectStructure os = new ObjectStructure();
//给结构增加一个节点
os.add(new NodeA());
//给结构增加一个节点
os.add(new NodeB());
//创建一个访问者
Visitor visitor = new VisitorA();
os.action(visitor);
}
}
2.3 优缺点
-
访问者模式的优点
- 好的扩展性。能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
- 好的复用性。可以通过访问者来定义整个对象结构通用的功能,从而提高复用程度。
- 分离无关行为。可以通过访问者来分离无关的行为,把相关的行为封装在一起,构成一个访问者,这样每一个访问者的功能都比较单一。
-
访问者模式的缺点
- 对象结构变化很困难。不适用于对象结构中的类经常变化的情况,因为对象结构发生了改变,访问者的接口和访问者的实现都要发生相应的改变,代价太高。
- 破坏封装。访问者模式通常需要对象结构开放内部数据给访问者和ObjectStructrue,这破坏了对象的封装性。
3 适用场景
- 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。
4 总结
访问者模式是一种集中规整模式,特别适用于大规模重构的项目,在这一个阶段需求已经非常清晰,原系统的功能点也已经明确,通过访问者模式可以很容易把一些功能进行梳理,达到最终目的——功能集中化,如一个统一的报表运算、UI展现等,我们还可以与其他模式混编建立一套自己的过滤器或者拦截器,请大家参考混编模式的相关章节。
参考书籍及文章
1.《Java与模式》,电子工业出版社,阎宏
- 《大话设计模式》,清华大学出版社,程杰
- 《设计模式——可复用面向对象软件的基础》,机械工业出版社,Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides
- 《Head First 设计模式(中文版)》,中国电力出版社
- 《图说设计模式》,https://design-patterns.readthedocs.io/zh_CN/latest/index.html