模式说明

以不同地方的厨师对相同食材的处理为例描述访问者模式。例如对于鸡,广东厨师会按粤菜做法做成白斩鸡,而四川厨师会做成川菜辣子鸡。对于鱼也类似,广东厨师将其做成清蒸鱼而四川厨师会处理成水煮鱼。可以把厨师描述为访问者,食材是被访问对象,不同的访问者访问相同的对象有不同的结果。具有这种特征的行为模式就是访问者模式。

本示例中,厨师为抽象访问者,广东厨师和四川厨师为具体访问者。被访问事物是鸡和鱼,它们都继承一个抽象访问对象类。广东厨师处理(访问)鸡和鱼会做出白斩鸡和清蒸鱼,而四川厨师处理鸡和鱼会做出辣子鸡和水煮鱼。设置一个访问对象结构类,其内持有所有的访问对象,有管理访问对象的方法add(增加访问对象)和remove(移除访问对象)。在客户端声明一个访问对象结构,然后add具体的访问对象。接着声明具体访问者,调用访问对象结构的访问方法accpet(传入具体访问者)。最终得到该访问者访问所有访问对象的结果。

结构

抽象访问者类
定义对所有访问对象的抽象访问方法。
具体访问者类
继承抽象访问者类,实现抽象访问方法。
抽象访问对象类
定义抽象访问方法accept,用于接受一个具体的访问者类的访问。
具体访问对象类
继承抽象访问对象类,实现抽象方法accept
访问对象结构类
持有访问对象的集合List<Material>,有若干管理访问对象的方法,有一个传入访问者的访问方法,方法内遍历其持有的访问对象并执行访问动作。

代码演示

  1. package com.yukiyama.pattern.behavior;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. /**
  5. * 访问者模式
  6. */
  7. public class VisitorDemo {
  8. public static void main(String[] args) {
  9. // 声明一个访问对象结构实例
  10. ObjectStructure obj = new ObjectStructure();
  11. // 增加访问对象至结构中
  12. obj.add(new ChickenMaterial());
  13. obj.add(new FishMaterial());
  14. // 声明访问者
  15. Cook gdCook = new GuangdongCook();
  16. Cook scCook = new SichuanCook();
  17. // 访问对象结构执行其accept方法,接收具体访问者的访问
  18. // 输出“粤菜白斩鸡”,“粤菜清蒸鱼”
  19. obj.accept(gdCook);
  20. // 输出”川菜辣子鸡“,”川菜水煮鱼“
  21. obj.accept(scCook);
  22. }
  23. }
  24. /**
  25. * 抽象访问者
  26. * 定义对所有访问对象的抽象访问方法,参数是所要访问的对象。
  27. * 下例抽象访问者为厨师,访问对象是鸡和鱼。
  28. */
  29. abstract class Cook{
  30. public abstract void make(ChickenMaterial chicken);
  31. public abstract void make(FishMaterial fish);
  32. }
  33. /**
  34. * 具体访问者
  35. * 继承抽象访问者类,实现抽象方法。
  36. * 下例是广东厨师访问鸡和鱼的动作,分别处理为粤菜白斩鸡和粤菜清蒸鱼。
  37. */
  38. class GuangdongCook extends Cook {
  39. @Override
  40. public void make(ChickenMaterial chicken) {
  41. System.out.println("粤菜白斩鸡");
  42. }
  43. @Override
  44. public void make(FishMaterial fish) {
  45. System.out.println("粤菜清蒸鱼");
  46. }
  47. }
  48. /**
  49. * 具体访问者
  50. * 下例是四川厨师访问鸡和鱼的动作,分别处理为川菜辣子鸡和川菜水煮鱼。
  51. */
  52. class SichuanCook extends Cook {
  53. @Override
  54. public void make(ChickenMaterial chicken) {
  55. System.out.println("川菜辣子鸡");
  56. }
  57. @Override
  58. public void make(FishMaterial fish) {
  59. System.out.println("川菜水煮鱼");
  60. }
  61. }
  62. /**
  63. * 抽象访问对象
  64. * 定义抽象访问方法accept(Cook cook),用于接受一个具体的访问者类的访问。
  65. */
  66. abstract class Material{
  67. public abstract void accept(Cook cook);
  68. }
  69. /**
  70. * 具体访问对象
  71. * 实现抽象类中的抽象方法accept(Cook cook)。传入具体访问者,调用访问者
  72. * 的行为方法(传入此时的访问对象指针this)。
  73. */
  74. class ChickenMaterial extends Material{
  75. @Override
  76. public void accept(Cook cook) {
  77. cook.make(this);
  78. }
  79. }
  80. /**
  81. * 具体访问对象
  82. */
  83. class FishMaterial extends Material{
  84. public void accept(Cook cook) {
  85. cook.make(this);
  86. }
  87. }
  88. /**
  89. * 访问对象结构类
  90. * 持有访问对象的集合List<Material>,管理访问对象,有增加访问对象方法add,
  91. * 移除访问对象方法remove,执行访问者对访问对象的访问动作accept方法。该
  92. * 方法内用for-each遍历该结构类持有的访问对象集合,并对每一个访问对象执行
  93. * 其accpet方法。
  94. */
  95. class ObjectStructure{
  96. private List<Material> materials = new ArrayList<>();
  97. public void add(Material material) {
  98. if(!materials.contains(material)){
  99. materials.add(material);
  100. }
  101. }
  102. public void remove(Material material) {
  103. if(materials.contains(material)) {
  104. materials.remove(material);
  105. }
  106. }
  107. public void accept(Cook cook) {
  108. for(Material m : materials) {
  109. m.accept(cook);
  110. }
  111. }
  112. }