1. <?php
    2. header("Content-type: text/html; charset=utf-8");
    3. /**
    4. * 观察者模式应用场景实例
    5. * 场景描述:
    6. * 以购票为核心业务(此模式不限于该业务),但围绕购票会产生不同的其他逻辑,如:
    7. * 1、购票后记录文本日志
    8. * 2、购票后记录数据库日志
    9. * 3、购票后发送短信
    10. * 4、购票送抵扣卷、兑换卷、积分
    11. * 5、其他各类活动等
    12. *
    13. * 传统解决方案:
    14. * 在购票逻辑等类内部增加相关代码,完成各种逻辑。
    15. *
    16. * 存在问题:
    17. * 1、一旦某个业务逻辑发生改变,如购票业务中增加其他业务逻辑,需要修改购票核心文件、甚至购票流程。
    18. * 2、日积月累后,文件冗长,导致后续维护困难。
    19. *
    20. * 存在问题原因主要是程序的"紧密耦合",使用观察模式将目前的业务逻辑优化成"松耦合",达到易维护、易修改的目的,
    21. * 同时也符合面向接口编程的思想。
    22. *
    23. * 观察者模式典型实现方式:
    24. * 1、定义2个接口:观察者(通知)接口、被观察者(主题)接口
    25. * 2、定义2个类,观察者对象实现观察者接口、主题类实现被观者接口
    26. * 3、主题类注册自己需要通知的观察者
    27. * 4、主题类某个业务逻辑发生时通知观察者对象,每个观察者执行自己的业务逻辑。
    28. *
    29. * 示例:如以下代码
    30. *
    31. */
    32. date_default_timezone_set('PRC'); //设置中国时区
    33. #===================定义观察者、被观察者接口============
    34. /**
    35. *
    36. * 观察者接口(通知接口)
    37. *
    38. */
    39. interface ITicketObserver //观察者接口
    40. {
    41. function onBuyTicketOver($sender, $args); //得到通知后调用的方法
    42. }
    43. /**
    44. *
    45. * 主题接口
    46. *
    47. */
    48. interface ITicketObservable //被观察对象接口
    49. {
    50. function addObserver($observer); //提供注册观察者方法
    51. }
    52. #====================主题类实现========================
    53. /**
    54. *
    55. * 主题类(购票)
    56. *
    57. */
    58. //实现主题接口(被观察者)
    59. class HipiaoBuy implements ITicketObservable
    60. {
    61. private $_observers = array(); //通知数组(观察者)
    62. public function buyTicket($ticket) //购票核心类,处理购票流程
    63. {
    64. // TODO 购票逻辑
    65. //循环通知,调用其onBuyTicketOver实现不同业务逻辑
    66. foreach ($this->_observers as $obs)
    67. $obs->onBuyTicketOver($this, $ticket); //$this 可用来获取主题类句柄,在通知中使用
    68. }
    69. //添加通知
    70. public function addObserver($observer) //添加N个通知
    71. {
    72. $this->_observers [] = $observer;
    73. }
    74. }
    75. #=========================定义多个通知====================
    76. //短信日志通知
    77. class HipiaoMSM implements ITicketObserver
    78. {
    79. public function onBuyTicketOver($sender, $ticket)
    80. {
    81. echo date('Y-m-d H:i:s'), "短信日志记录:购票成功:$ticket" . PHP_EOL;;
    82. }
    83. }
    84. //文本日志通知
    85. class HipiaoTxt implements ITicketObserver
    86. {
    87. public function onBuyTicketOver($sender, $ticket)
    88. {
    89. echo date('Y-m-d H:i:s'), "文本日志记录:购票成功:$ticket<br>" . PHP_EOL;;
    90. }
    91. }
    92. //抵扣卷赠送通知
    93. class HipiaoDiKou implements ITicketObserver
    94. {
    95. public function onBuyTicketOver($sender, $ticket)
    96. {
    97. echo date('Y-m-d H:i:s'), "赠送抵扣卷:购票成功:$ticket 赠送10元抵扣卷1张<br>" . PHP_EOL;;
    98. }
    99. }
    100. #============================用户购票====================
    101. $buy = new HipiaoBuy ();
    102. //根据不同业务逻辑加入各种通知
    103. $buy->addObserver(new HipiaoMSM()); //把短信通知类对象添加$_observers数组中
    104. $buy->addObserver(new HipiaoTxt()); //把文本通知类对象添加$_observers数组中
    105. $buy->addObserver(new HipiaoDiKou());//把赠送通知类对象添加$_observers数组中
    106. //购票
    107. $buy->buyTicket("一排一号");