访问者模式(Visitor Pattern),将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离,是行为类模式中最复杂的一种模式。
**
在现实生活中,有些集合对象存在多种不同的元素,且每种元素也存在多种不同的访问者和处理方式。例如,公园中存在多个景点,也存在多个游客,不同的游客对同一个景点的评价可能不同;医院医生开的处方单中包含多种药元素,査看它的划价员和药房工作人员对它的处理方式也不同,划价员根据处方单上面的药品名和数量进行划价,药房工作人员根据处方单的内容进行抓药。

这样的例子还有很多,例如,电影或电视剧中的人物角色,不同的观众对他们的评价也不同;还有顾客在商场购物时放在“购物车”中的商品,顾客主要关心所选商品的性价比,而收银员关心的是商品的价格和数量。

这些被处理的数据元素相对稳定而访问方式多种多样的数据结构,如果用“访问者模式”来处理比较方便。访问者模式能把处理方法从数据结构中分离出来,并可以根据需要增加新的处理方法,且不用修改原来的程序代码与数据结构,这提高了程序的扩展性和灵活性。
**
访问者模式组成结构如下:

Visitor(抽象访问者) 定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素
Concrete Visitor(具体访问者) 实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么
Element(抽象元素) 声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数
Concrete Element(具体原色) 实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作
Object Structure(对象结构) 是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现

访问者模式的优点

  1. 扩展性好。能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能
  2. 复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度
  3. 灵活性好。访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构
  4. 符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一

访问者模式的缺点

  1. 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”
  2. 破坏封装。访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性
  3. 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类

访问者模式使用场景

  1. 对象结构相对稳定,但其操作算法经常变化的程序
  2. 对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构
  3. 对象结构包含很多类型的对象,希望对这些对象实施一些依赖于其具体类型的操作

访问者模式使用示例

  1. public class VisitorPattern {
  2. /**
  3. * 定义抽象访问者,为每个元素添加访问操作
  4. */
  5. interface Visitor {
  6. void visit(ElementA elementA);
  7. void visit(ElementB elementB);
  8. }
  9. /**
  10. * 定义抽象元素类,接收访问者对象
  11. */
  12. interface Element {
  13. void accept(Visitor visitor);
  14. }
  15. static class ElementA implements Element {
  16. @Override
  17. public void accept(Visitor visitor) {
  18. visitor.visit(this);
  19. }
  20. public Object operateA() {
  21. return "对ElementA进行了操作";
  22. }
  23. }
  24. static class ElementB implements Element {
  25. @Override
  26. public void accept(Visitor visitor) {
  27. visitor.visit(this);
  28. }
  29. public Object operateB() {
  30. return "对ElementB进行了操作";
  31. }
  32. }
  33. static class VisitorA implements Visitor {
  34. @Override
  35. public void visit(ElementA elementA) {
  36. System.out.println("具体访问者ElementA: " + elementA.operateA());
  37. }
  38. @Override
  39. public void visit(ElementB elementB) {
  40. System.out.println("具体访问者ElementA: " + elementB.operateB());
  41. }
  42. }
  43. static class VisitorB implements Visitor {
  44. @Override
  45. public void visit(ElementA elementA) {
  46. System.out.println("具体访问者ElementB: " + elementA.operateA());
  47. }
  48. @Override
  49. public void visit(ElementB elementB) {
  50. System.out.println("具体访问者ElementB: " + elementB.operateB());
  51. }
  52. }
  53. static class ObjectStructure {
  54. private final List<Element> elements = new ArrayList<>();
  55. void accept(Visitor visitor) {
  56. Iterator<Element> iterator = elements.iterator();
  57. while (iterator.hasNext()) {
  58. iterator.next().accept(visitor);
  59. }
  60. }
  61. public void add(Element element) {
  62. elements.add(element);
  63. }
  64. }
  65. public static void main(String[] args) {
  66. ObjectStructure structure = new ObjectStructure();
  67. structure.add(new ElementA());
  68. structure.add(new ElementB());
  69. structure.accept(new VisitorA());
  70. structure.accept(new VisitorB());
  71. }
  72. }

程序运行结果如下:

:::success 具体访问者ElementA: 对ElementA进行了操作
具体访问者ElementA: 对ElementB进行了操作

具体访问者ElementB: 对ElementA进行了操作
具体访问者ElementB: 对ElementB进行了操作 :::