定义:使用一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。通过访问者来访问自身的一些方法。accept方法的参数为访问者,访问者方法visit通过参数元素访问元素本身。
角色:
抽象访问者:抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法中的参数定义哪些对象是可以被访问的。
访问者:实现抽象访问者所声明的方法,它影响到访问者访问到一个类后该干什么,要做什么事情。
抽象元素类:接口或者抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的。抽象元素一般有两类方法,一部分是本身的业务逻辑,另外就是允许接收哪类访问者来访问。
元素类:实现抽象元素类所声明的accept方法,通常都是visitor.visit(this),基本上已经形成一种定式了。
结构对象:一个元素的容器,一般包含一个容纳多个不同类、不同接口的容器,如List、Set、Map等,在项目中一般很少抽象出这个角色。
结构图:
优点:
1、符合单一职责原则。凡是适用访问者模式的场景中,元素类中需要封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作,使用访问者模式一方面符合单一职责原则,另一方面,因为被封装的操作通常来说都是易变的,所以当发生变化时,就可以在不改变元素类本身的前提下,实现对变化部分的扩展。
2、优秀的扩展性。元素类可以通过接受不同的访问者来实现对不同操作的扩展。 3、灵活性。
缺点:1、具体元素对访问者公布细节,违反了迪米特原则。
2、具体元素变更比较困难。
3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
使用:创建一个定义接受操作的 ComputerPart 接口。Keyboard、Mouse、Monitor 和 Computer 是实现了 ComputerPart接口的实体类。我们将定义另一个接口 ComputerPartVisitor,它定义了访问者类的操作。Computer 使用实体访问者来执行相应的动作。
1.定义一个表示元素的接口:
public interface ComputerPart { public void accept(ComputerPartVisitor computerPartVisitor); }
2.创建扩展了上述类的实体类。
public class Keyboard implements ComputerPart { public Override void accept(ComputerPartVisitor computerPartVisitor) { computerPartVisitor.visit(this); } } public class Monitor implements ComputerPart { public Override void accept(ComputerPartVisitor computerPartVisitor) { computerPartVisitor.visit(this); } } public class Mouse implements ComputerPart { public Override void accept(ComputerPartVisitor computerPartVisitor) { computerPartVisitor.visit(this); } } public class Computer implements ComputerPart { ComputerPart[] parts; public Computer() { parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()}; } public Override void accept(ComputerPartVisitor computerPartVisitor) { for (int i = 0; i < parts.length; i++) { parts[i].accept(computerPartVisitor); } computerPartVisitor.visit(this); } }
3.定义一个表示访问者的接口。
public interface ComputerPartVisitor { public void visit(Computer computer); public void visit(Mouse mouse); public void visit(Keyboard keyboard); public void visit(Monitor monitor); }
4.创建实现了上述类的实体访问者。
public class ComputerPartDisplayVisitor implements ComputerPartVisitor { public Override void visit(Computer computer) { System.out.println("Displaying Computer."); } public Override void visit(Mouse mouse) { System.out.println("Displaying Mouse."); } public Override void visit(Keyboard keyboard) { System.out.println("Displaying Keyboard."); } public Override void visit(Monitor monitor) { System.out.println("Displaying Monitor."); } }
5.使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。
public class VisitorPatternDemo { public static void main(String[] args) { ComputerPart computer = new Computer(); computer.accept(new ComputerPartDisplayVisitor()); } }