访问者模式
Visitor Pattern:访问者模式,是GoF23种设计模式中属于行为型模式的一种。
访问者模式的定义为:表示一个作用于某对象结构中的个元素的操作,可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
实际上来说,就是定义了一个访问者类,而各个元素对象接收这个访问者对象进行操作,如果想要换成不同的操作,简单的修改访问者对象即可让这些元素对象执行不同的操作。
结构
结合类图分析,访问者模式比较负责,一共有着五个对象角色构成:
- 抽象访问者(Visitor)对象:为对象结构中的具体的元素对象声明一个访问操作。这个访问操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色。
- 具体访问者(Concrete Visitor)对象:实现抽象访问者声明的操作。
- 抽象元素(Element)对象:需要定义一个统一的接收访问的操作,参数需要的是一个访问者。
- 具体元素(Concrete Element)对象:实现抽象元素对象定义的接收访问操作接口方法。
- 对象结构(Object Structure)对象:这是一个必备的角色,可以枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素。
举例
- 访问者模式的使用位于现实生活中,就可以类比于访谈或者说是采访。作为记者或者主持人的就是访问者,被采访的人需要接收你的访问,然后你需要通过它的话语得出自己所需要的信息。
注意
- 访问者模式的使用,也是单一职责原则的使用,单单就是这个模式就是十分符合单一职责原则的。
- 同时,访问者模式的扩展性也是很强的,因为元素只要接收不同的访问者对象就可以实现对于不同的操作的扩展了。
- 不好之处就是访问者对象的细节是需要对具体元素给出的,不然具体元素调用不了,所以违反了迪米特原则。
- 另一方面就是违反了依赖倒置的原则,因为具体元素的调用需要依赖的是具体的访问者对象,而不是抽象访问者。也就是说依赖了具体类而不是依赖抽象。
- 访问者的目的就是要把处理从数据结构分离出来,而且访问者模式对于新增加操作来说是很容易的,也就是扩展性,对于操作的扩展性是很强的。
一个小DEMO
-
场景
访问者模式较为麻烦,为了简便起见,就以通用代码的格式进行代码描述。
-
抽象访问者及其具体访问者的定义
/** * 访问者模式——抽象访问者角色 * @author wq */ public interface Visitor { // 为每一个具体元素对象都声明一个访问的操作方法 void visitA(ConcreateElementA a); void visitB(ConcreateElementB b); } //------------------------------------------------------------------------------ /** * 访问者模式——具体访问者角色A * @author wq */ public class ConcreateVisitorA implements Visitor{ @Override public void visitA(ConcreateElementA a) { System.out.println("具体元素对象 A 被访问者 A 访问"); } @Override public void visitB(ConcreateElementB b) { System.out.println("具体元素对象 B 被访问者 A 访问"); } } //------------------------------------------------------------------------------ /** * 访问者模式——具体访问者角色B * @author wq */ public class ConcreateVisitorB implements Visitor{ @Override public void visitA(ConcreateElementA a) { System.out.println("具体元素对象 A 被访问者 B 访问"); } @Override public void visitB(ConcreateElementB b) { System.out.println("具体元素对象 B 被访问者 B 访问"); } } //------------------------------------------------------------------------------
-
抽象元素和具体元素的定义
/** * 访问者模式——抽象元素角色 * @author wq */ public interface Element { // 需要的就是定义一个接收访问的方法 void accept(Visitor visitor); } //------------------------------------------------------------------------------ /** * 访问者模式——具体元素对象A * @author wq */ public class ConcreateElementA implements Element{ @Override public void accept(Visitor visitor) { visitor.visitA(this); } } //------------------------------------------------------------------------------ /** * 访问者模式——具体元素对象B * @author wq */ public class ConcreateElementB implements Element{ @Override public void accept(Visitor visitor) { visitor.visitB(this); } } //------------------------------------------------------------------------------
-
对象结构的定义
/** * 访问者模式——对象结构角色 * @author wq */ import java.util.ArrayList; import java.util.List; public class ObjectStructure { // 可以枚举它的元素 private List<Element> elements = new ArrayList<Element>(); public void addElement(Element element) { elements.add(element); } public void removeElement(Element element) { elements.remove(element); } //还可以提供一个高层的接口 public void accept(Visitor visitor) { for (Element element : elements) { element.accept(visitor); } } }
-
测试类
/** * 访问者模式——测试类 * @author wq */ public class Main { public static void main(String[] args) { ObjectStructure objectStructure = new ObjectStructure(); objectStructure.addElement(new ConcreateElementA()); objectStructure.addElement(new ConcreateElementB()); ConcreateVisitorA a = new ConcreateVisitorA(); ConcreateVisitorB b = new ConcreateVisitorB(); objectStructure.accept(a); objectStructure.accept(b); } }
-
测试一波
具体元素对象 A 被访问者 A 访问 具体元素对象 B 被访问者 A 访问 具体元素对象 A 被访问者 B 访问 具体元素对象 B 被访问者 B 访问
完成!!!