访问者模式(Visitor)
访问者模式封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用与这些元素的新的操作。
访问者模式的角色划分:
抽象访问者角色(Visitor): 该角色声明一个或多个访问操作,定义访问者可以访问哪些元素。
具体访问者角色(Concrete Visitor): 该角色实现抽象访问者角色中的各个访问操作。
抽象元素角色(Element): 该角色声明一个接受操作,接受一个访问者对象。
具体元素角色(Concrete Element): 该角色实现抽象元素中的接受操作。
结构对象角色(Object Structure): 该角色有以下责任:可以遍历结构中的所有元素,如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素,也可以设计一个复合对象或者一个集合,如List或者Set。
优点
-
扩展性好。能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
-
复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
-
灵活性好。访问者模式将数据结构与用作于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
-
符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。
缺点
- 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
- 破坏封装。访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性。
- 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类。
使用场景
- 数据结构稳定,作用于数据结构的操作经常变化的时候。
- 当一个数据结构中,一些元素类需要负责与其不相关的操作的时候,为了将这些操作分离出去,以减少这些元素类的职责时,可以使用访问者模式。
- 有时在对数据结构上的元素进行操作的时候,需要区分具体的类型,这时使用访问者模式可以针对不同的类型,在访问者类中定义不同的操作,从而去除掉类型判断。
具体实现
-
定义一个表示元素的接口
//抽象元素角色 public interface ComputerPart { //接收计算机访问者 public void accept(ComputerPartVisitor computerPartVisitor); }
-
创建扩展了上述类的实体类。
//Keyboard:键盘 public class Keyboard implements ComputerPart { @Override public void accept(ComputerPartVisitor computerPartVisitor) { computerPartVisitor.visit(this); } } //Monitor 显示器; public class Monitor implements ComputerPart { @Override public void accept(ComputerPartVisitor computerPartVisitor) { computerPartVisitor.visit(this); } } //Mouse:鼠标 public class Mouse implements ComputerPart { @Override public void accept(ComputerPartVisitor computerPartVisitor) { computerPartVisitor.visit(this); } } //Computer:电脑 public class Computer implements ComputerPart { ComputerPart[] parts; public Computer(){ parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()}; } @Override public void accept(ComputerPartVisitor computerPartVisitor) { for (int i = 0; i < parts.length; i++) { parts[i].accept(computerPartVisitor); } computerPartVisitor.visit(this); } }
-
定义一个表示访问者的接口
public interface ComputerPartVisitor { public void visit(Computer computer); public void visit(Mouse mouse); public void visit(Keyboard keyboard); public void visit(Monitor monitor); }
-
创建实现了上述类的实体访问者。
public class ComputerPartDisplayVisitor implements ComputerPartVisitor { @Override public void visit(Computer computer) { System.out.println("Displaying Computer."); } @Override public void visit(Mouse mouse) { System.out.println("Displaying Mouse."); } @Override public void visit(Keyboard keyboard) { System.out.println("Displaying Keyboard."); } @Override public void visit(Monitor monitor) { System.out.println("Displaying Monitor."); } }
-
使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分
public class VisitorPatternDemo { public static void main(String[] args) { ComputerPart computer = new Computer(); computer.accept(new ComputerPartDisplayVisitor()); } }