若转载教程,请注明出自SW-X框架官方文档1

    1. <?php
    2. /**
    3. * 设计模式之访问者模式
    4. * 使用场景:实体是固定的,但行为却是多变的
    5. * 小黄牛
    6. */
    7. header("Content-type: text/html; charset=utf-8");
    8. /**
    9. * 抽象出 实体类
    10. */
    11. abstract class Entity{
    12. public $people_name; // 人的名称
    13. /**
    14. * 触发行为
    15. * $Visitor 对应行为的实例
    16. */
    17. public abstract function Accept($Visitor);
    18. }
    19. /**
    20. * 创建一个 男性
    21. */
    22. class VMan extends Entity{
    23. function __construct(){
    24. $this->people_name = "男人";
    25. }
    26. public function Accept($Visitor){
    27. $Visitor->VManRelease($this);
    28. }
    29. }
    30. /**
    31. * 创建一个 女性
    32. */
    33. class VWoman extends Entity{
    34. function __construct(){
    35. $this->people_name = "女人";
    36. }
    37. public function Accept($Visitor){
    38. $Visitor->VWomanRelease($this);
    39. }
    40. }
    41. /**
    42. * 抽象出 行为类
    43. */
    44. abstract class Behavior{
    45. protected $bh_name;
    46. /**
    47. * 行为逻辑 - 男性
    48. * $ResNew 对应实体的实例
    49. */
    50. public abstract function VManRelease($ResNew);
    51. /**
    52. * 行为逻辑 - 女性
    53. * $ResNew 对应实体的实例
    54. */
    55. public abstract function VWomanRelease($ResNew);
    56. }
    57. /**
    58. * 创建一个 吃东西行为
    59. */
    60. class Eat extends Behavior{
    61. public function __construct(){
    62. $this->bh_name = "吃东西";
    63. }
    64. public function VManRelease($VMan){
    65. echo "{$VMan->people_name} : {$this->bh_name}时,都很粗鲁。<br/>";
    66. }
    67. public function VWomanRelease($VMan){
    68. echo "{$VMan->people_name} : {$this->bh_name}时,都很斯文。<br/>";
    69. }
    70. }
    71. /**
    72. * 创建一个 运动行为
    73. */
    74. class Motion extends Behavior{
    75. public function __construct(){
    76. $this->bh_name = "运动";
    77. }
    78. public function VManRelease($VMan){
    79. echo "{$VMan->people_name} : {$this->bh_name}时,大汗淋漓。<br/>";
    80. }
    81. public function VWomanRelease($VMan){
    82. echo "{$VMan->people_name} : {$this->bh_name}时,休闲漫步。<br/>";
    83. }
    84. }
    85. /**
    86. * 设计一个 结构对象类,用于聚合实体信息
    87. */
    88. class Object{
    89. private $entity = array(); // 存储实体对象
    90. # 新增实体
    91. public function Add($entity){
    92. array_push($this->entity, $entity);
    93. }
    94. # 移除实体
    95. public function Remove($entity){
    96. foreach($this->entity as $k=>$v) {
    97. if($v==$entity) {
    98. unset($this->entity[$k]);break;
    99. }
    100. }
    101. }
    102. # 查看对应行为描述
    103. public function Display($Visitor){
    104. foreach ($this->entity as $v) {
    105. $v->Accept($Visitor);
    106. }
    107. }
    108. }
    109. # 先聚合实体
    110. $os = new Object();
    111. $os->Add(new VMan());
    112. $os->Add(new VWoman());
    113. # 查看吃东西的行为
    114. $os->Display(new Eat());
    115. # 查看运动的行为
    116. $os->Display(new Motion());

    前言

    1. 在逻辑上,访问者模式 策略模式是非常相识的;
    2. 乍一看,其实两者都挺像的,都是实体类依赖了外部实体的算法,但是:
    3. 对于策略模式:首先你是有一堆算法,然后在不同的逻辑中去使用;
    4. 对于访问者模式:实体的【结构是稳定的】,但是结构中元素的算法却是多变的,比如就像人吃饭这个动作是稳定不变的,但是具体吃的行为却又是多变的;

    浏览器输出

    1. 男人 : 吃东西时,都很粗鲁。
    2. 女人 : 吃东西时,都很斯文。
    3. 男人 : 运动时,大汗淋漓。
    4. 女人 : 运动时,休闲漫步。

    访问者模式

    1. 1.抽象实体类(Entity):定义一个触发行为的Accept()方法,它以一个行为实例作为参数。
    2. 2.具体实体(Man):实现了抽象实体所定义的操作接口,并按照自身情况调用对应的行为方法。
    3. 3.抽象行为(Behavior):为实体,抽象出一系列可供访问的操作接口。该操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色,这样访问者就可以通过该元素角色的特定接口直接访问它。
    4. 4.具体行为(Success):实现了实体声明的接口。
    5. 5.结构对象(ObjectStruct):这是使用访问者模式必备的角色。它具备以下特性:能枚举它的元素;可以提供一个高层接口以允许访问者访问它的元素;如有需要,可以设计成一个复合对象或者一个聚集(如一个列表或无序集合)。

    应用场景与优势

    1. 1、一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
    2. 2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor模式使得你可以将相关的操作集中起来定义在一个类中。
    3. 3、当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
    4. 4、定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。