设计模式24——访问者模式
写文章的初心主要是用来帮助自己快速的回忆这个模式该怎么用,主要是下面的UML图可以起到大作用,在你学习过一遍以后可能会遗忘,忘记了不要紧,只要看一眼UML图就能想起来了。同时也请大家多多指教。
访问者模式(Visitor)
对象行为型模式。
目录
一、概述
1.1、直观的理解:
1.2、主要角色:
1.3、描述上述对象之间关系的UML图:
1.4、适用场景:
二、代码举例
2.1、对象之间的关系用UML图描述如下:
2.2、Java代码如下:
一、概述
1、表示一个作用于某对象结构中的各个元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作;
2、这算法应当是针对这数据结构里每一个对象建对应的处理,也就是算法对象里有一整个操作集合,使得每一个对象都可以根据不同的具体算法都同一时间段内单独的操作一下。而针对不同的时间段,又可以新建不同的算法类,同样算法类里也应该有在同一时间段里对那些数据结构类群里的所有对象的操作。
1.1、直观的理解:
假设有3个元素,且对这些元素有两种操作需要实现,使用访问者模式我们逻辑上的思考应该是:
但在代码实现上,我们还需要再加一个枚举元素的类,他存储了所有相关的元素,并且可以枚举它们,方便访问者操作那些元素。
就拿访问者A访问元素1、2、3为例,活动图如下:
1.2、主要角色:
- 访问者:访问者的抽象类或接口 + 访问者类,操作元素的类
- 元素:元素的抽象类或接口 + 元素类,被操作的对象
- 枚举元素类的类(ObjectStructure对象结构):保存着元素类的集合,并且可以遍历已保存的元素方便访问者访问
1.3、描述上述对象之间关系的UML图:
1.4、适用场景:
- 一个对象结构包含很多类对象,它们有着不同的接口,而你想对这些对象实施一些依赖于其具体类的操作
- 需要对一个对象结构中的对象进行很多不太并且不相关的操作,而你想要避免让这些操作“污染”这些对象的类
- 适合于数据结构相对稳定的系统。它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化
二、代码举例
假设有元素A和B,在它们之上有两类操作,那么设计出访问者1和2。这个例子比较简单,就不再详细分析了。但你可以把本例当做一个模板,然后灵活使用:
2.1、对象之间的关系用UML图描述如下:
2.2、Java代码如下:
访问者的抽象类:
abstract class Visitor {public abstract void visitConcreteElementA(ConcreteElementA concreteElementA);public abstract void visitConcreteElementB(ConcreteElementB concreteElementB);
}
元素的抽象类:
abstract class Element {public abstract void accept(Visitor visitor);
}
元素类A:
public class ConcreteElementA extends Element{@Overridepublic void accept(Visitor visitor) {visitor.visitConcreteElementA(this);}//其他操作
}
元素类B:
public class ConcreteElementB extends Element{@Overridepublic void accept(Visitor visitor) {visitor.visitConcreteElementB(this);}//其他操作
}
访问者1:
public class ConcreteVisitor1 extends Visitor {@Overridepublic void visitConcreteElementA(ConcreteElementA concreteElementA) {System.out.println(concreteElementA.getClass().getSimpleName() + "被" + this.getClass().getSimpleName() + "访问");}@Overridepublic void visitConcreteElementB(ConcreteElementB concreteElementB) {System.out.println(concreteElementB.getClass().getSimpleName() + "被" + this.getClass().getSimpleName() + "访问");}
}
访问者2:
public class ConcreteVisitor2 extends Visitor {@Overridepublic void visitConcreteElementA(ConcreteElementA concreteElementA) {System.out.println(concreteElementA.getClass().getSimpleName() + "被" + this.getClass().getSimpleName() + "访问");}@Overridepublic void visitConcreteElementB(ConcreteElementB concreteElementB) {System.out.println(concreteElementB.getClass().getSimpleName() + "被" + this.getClass().getSimpleName() + "访问");}
}
枚举元素类的类:
public class ObjectStructure {private List<Element> elements = new ArrayList<>();public void attach(Element element) {elements.add(element);}public void detach(Element element) {elements.remove(element);}public void accept(Visitor visitor) {for (Element element : elements) {element.accept(visitor);}}
}
主程序(发起请求的类):
public class Main {public static void main(String[] args) {ObjectStructure objectStructure = new ObjectStructure();objectStructure.attach(new ConcreteElementA());objectStructure.attach(new ConcreteElementB());objectStructure.accept(new ConcreteVisitor1());objectStructure.accept(new ConcreteVisitor2());}
}
这里就不再举例了,可以把上面的Java例子复制到你本地,运行main函数试一下加深理解。这些代码都是我自己学习的时候根据一些教材手敲的,不存在bug可以直接运行。
如果觉得本文还不错,就请点个赞给作者一点鼓励吧!如果有建议,也请评论指教和讨论!