行为模式之访问者模式
访问者模式
定义:表示一个作用于某对象结构中的各元素的操作。它让我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
角色:访问者(Vistor)接口、具体访问者、访问元素(Element)接口、具体元素
理解:1.元素对象通常是“部分-整体”结构中的节点。2.客户端创建一个ConcreteVistoer,把它传给一个ConcreteElement,ConcreteElement的所有集合都接受ConcreteVistoer的访问。
适用:
- 一个复杂的对象结构包含很多其他对象,它们有不同的接口,但是相对这些对象实施一些依赖于其具体类型的操作。
- 需要对一个组合结构中的对象进行很多不相关的操作,但是不想让这些操作污染这些对象的类。可将相关操作集中起来,定义在一个访问者类中,并在需要在访问者中定义的操作时使用它。
- 定义复杂的结构类很少作修改,但经常需要向其添加新的操作。
类图:
根据角色给出示意性代码:
抽象访问者
/**
* 访问者接口
*
* @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);
}
}
访问者接口——通过重载实现了不同类型的不同访问
/**
* 集合访问者接口
*
* @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);
}
}
}
总结
访问者模式有比较好的扩展性,看看访问者代码,我们如果要新增一个访问者:市领导人,只需新增市领导人类,便可实现。当然也有它不好的地方,就是把被访问者暴露给访问者,使得访问者可以直接了解被访问者的所有东西。明白了优缺点,才能更好的在实际中运用,一般访问者模式运用于要求遍历多个不同的对象的场景。