概述
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。简单来说,访问者模式就是一种分离对象数据结构与行为的方法,通过这种分离,可达到为一个被访问者动态添加新的操作而无需做其它的修改的效果。
访问者模式把数据结构和作用于结构上的操作解耦合,使得操作集合可相对自由地演化。访问者模式适用于数据结构相对稳定算法又易变化的系统。因为访问者模式使得算法操作增加变得容易。若系统数据结构对象易于变化,经常有新的数据对象增加进来,则不适合使用访问者模式。访问者模式的优点是增加操作很容易,因为增加操作意味着增加新的访问者。访问者模式将有关行为集中到一个访问者对象中,其改变不影响系统数据结构。其缺点就是增加新的数据结构很困难。—— From 百科
涉及角色
- Visitor
抽象访问者:抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以被访问的。 - ConcreteVisitor
具体访问者:它影响访问者访问到一个类后该怎么干,要做什么事情。 - Element
抽象元素:接口或者抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的。 - ConcreteElement
具体元素:实现accept方法,通常是visitor.visit(this),基本上都形成了一种模式了。 - ObjectStruture
结构对象:元素产生者,一般容纳在多个不同类、不同接口的容器,如List、Set、Map等,在项目中,一般很少抽象出这个角色。处理element角色的集合。
UML
使用场景
- 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作,也就说是用迭代器模式已经不能胜任的情景。
- 需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。
优点
- 好的扩展性
能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。 - 好的复用性
可以通过访问者来定义整个对象结构通用的功能,从而提高复用程度。 - 分离无关行为
可以通过访问者来分离无关的行为,把相关的行为封装在一起,构成一个访问者,这样每一个访问者的功能都比较单一。
缺点
- 对象结构变化很困难
不适用于对象结构中的类经常变化的情况,因为对象结构发生了改变,访问者的接口和访问者的实现都要发生相应的改变,代价太高。 - 破坏封装
访问者模式通常需要对象结构开放内部数据给访问者和ObjectStructrue,这破坏了对象的封装性。
代码示例
package com.designpattern.visitor;
public abstract class Node {
public abstract void accept(Visitor visitor);
}
package com.designpattern.visitor;
public class NodeA extends Node{
/**
* 接受操作
*/
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
/**
* NodeA特有的方法
*/
public String operationA(){
return "NodeA";
}
}
package com.designpattern.visitor;
public class NodeB extends Node{
/**
* 接受操作
*/
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
/**
* NodeA特有的方法
*/
public String operationB(){
return "NodeB";
}
}
package com.designpattern.visitor;
public interface Visitor {
public void visit(NodeA node);
public void visit(NodeB node);
}
package com.designpattern.visitor;
public class VisitorA implements Visitor {
@Override
public void visit(NodeA node) {
System.out.println("VisitorA:"+node.operationA());
}
/**
* 对应于NodeB的访问操作
*/
@Override
public void visit(NodeB node) {
System.out.println("VisitorA:"+node.operationB());
}
}
package com.designpattern.visitor;
public class VisitorB implements Visitor {
@Override
public void visit(NodeA node) {
System.out.println("VisitorB:"+node.operationA());
}
/**
* 对应于NodeB的访问操作
*/
@Override
public void visit(NodeB node) {
System.out.println("VisitorB:"+node.operationB());
}
}
package com.designpattern.visitor;
import java.util.ArrayList;
import java.util.List;
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);
}
}
package com.designpattern.visitor;
public class TestMain {
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);
}
}