-
Notifications
You must be signed in to change notification settings - Fork 0
访问者模式
ZHI-XINHUA edited this page Jan 11, 2019
·
1 revision
访问者模式属于行为型模式。 访问者模式的目的是封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构可以保存不变。
意图: 主要将数据结构与数据操作分离。
主要解决: 稳定的数据结构和易变的操作耦合问题。
何时使用: 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中。
如何解决: 在被访问的类里面加一个对外提供接待访问者的接口。
如下:一个集合中保存不同类型的对象,不同对象需要打印不一样的效果。在遍历的时候判断类型,这样做扩展性不高而且判断越来越多,不便于维护。
- 抽象访问者(Visitor)角色:声明一个或者多个访问操作,形成所有的具体元素角色必须实现的接口
- 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口,也就是抽象访问者所声明的各个访问操作
- 抽象节点(Node)角色:声明一个接受操作,接受一个访问者对象作为一个参量
- 具体节点角色(ConcreteNode):实现了抽象元素所规定的接受操作
- 结构对象(ObjectStructure)角色:有如下一下责任
- 可以遍历结构中的所有元素
- 如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素
- 如果需要,可以设计成一个复合对象或者一个聚集,如列(List)或集合(Set)
(1)访问者接口,visit
访问每一个节点。ps:违反了依赖倒置原则,依赖了具体类,没有依赖抽象
/**
* 抽象访问者(Visitor)角色:声明一个或者多个访问操作,形成所有的具体元素角色必须实现的接口
*/
public interface Visitor {
/**
* 对于ModeA的访问操作
* @param nodeA
*/
void visit(NodeA nodeA);
/**
* 对于NodeB的访问操作
* @param nodeB
*/
void visit(NodeB nodeB);
}
(2)具体访问者
/**
* 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色所声明的接口,也就是抽象访问者所声明的各个访问操作
*/
public class VisitorA implements Visitor {
@Override
public void visit(NodeA nodeA) {
System.out.println("VisitorA:"+nodeA.operationA());
}
@Override
public void visit(NodeB nodeB) {
System.out.println("VisitorA:"+nodeB.operationB());
}
}
class VisitorB implements Visitor {
@Override
public void visit(NodeA nodeA) {
System.out.println("VisitorB:"+nodeA.operationA());
}
@Override
public void visit(NodeB nodeB) {
System.out.println("VisitorB:"+nodeB.operationB());
}
}
(3)抽象节点(Node)角色,值得注意的是,抽象方法accept
必须接受访问者对象,目的是让访问者可以访问节点
/**
* 抽象节点(Node)角色:声明一个接受操作,接受一个访问者对象作为一个参量
*/
abstract public class Node {
/**
* 接受操作
* @param visitor
*/
public abstract void accept(Visitor visitor);
}
(4)具体节点角色(ConcreteNode):实现了抽象元素所规定的接受操作
/**
* 具体节点角色(ConcreteNode):实现了抽象元素所规定的接受操作
*/
public class NodeA extends Node{
/**
* 接受操作
* @param visitor
*/
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
/**
* NodeA特有方法
* @return
*/
public String operationA(){
return "NodeA is visited";
}
}
class NodeB extends Node {
/**
* 接受方法
* @param visitor
*/
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
/**
* NodeA特有方法
* @return
*/
public String operationB(){
return "NodeB is visited";
}
}
(5)结构对象(ObjectStructure)角色,提供遍历结构中的所有元素和保存节点集合
/**
* 结构对象(ObjectStructure)角色:有如下一下责任
* 1、可以遍历结构中的所有元素
* 2、如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素
* 3、如果需要,可以设计成一个复合对象或者一个聚集,如列(List)或集合(Set)
*/
public class ObjectStructure {
private Vector nodes;
private Node node;
public ObjectStructure(){
nodes = new Vector();
}
/**
* 执行访问操作
* @param visitor
*/
public void traverse(Visitor visitor){
Enumeration enumeration = nodes.elements();
while(enumeration.hasMoreElements()){
Node node = (Node) enumeration.nextElement();
//访问操作
node.accept(visitor);
}
}
/**
* 添加元素
* @param node
*/
public void addNode(Node node){
nodes.add(node);
}
}
测试:
public static void main(String[] args) {
//创建结果对象,保存节点
ObjectStructure structure = new ObjectStructure();
structure.addNode(new NodeA());
structure.addNode(new NodeB());
//添加访问者A
Visitor visitorA = new VisitorA();
//遍历
structure.traverse(visitorA);
//添加访问者B
Visitor visitorB = new VisitorB();
//遍历
structure.traverse(visitorB);
}
VisitorA:NodeA is visited
VisitorA:NodeB is visited
VisitorB:NodeA is visited
VisitorB:NodeB is visited
- 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。
- 访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器
优点: 1、符合单一职责原则。 2、优秀的扩展性。 3、灵活性。
缺点: 1、具体元素对访问者公布细节,违反了迪米特原则。 2、具体元素变更比较困难。 3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
参考:菜鸟教程-访问者模式
设计模式