作者简介:

       姜海强:闷骚码农,互联网行业摸爬滚打数余载,先后担任中国体育直播TV主程、网信集团先锋支付架构师、奇虎360服务器端资深开发。热爱技术,喜欢分享,热衷领域:PHP/Golang语言、面向对象设计模式、Redis、Yaf、Yii2、微服务等。

视频课程

yaf+yar微服务-腾讯课堂
yaf+yar微服务-51CTO学院
CSDN学院

Github

个人主页
swoole-boot
roach
roach-orm

QQ群:

姜海强的QQ群

公众号:

360tryst公众号

策略模式

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化,即封装变化的算法。

策略模式的本质是将算法封装起来。下面看一个常见的代码

  1. <?php
  2. /**
  3. * @param string $driver
  4. * @param string $msg
  5. * @datetime 2020/7/17 5:42 PM
  6. * @author roach
  7. * @email jhq0113@163.com
  8. */
  9. function log($driver, $msg) {
  10. switch ($driver) {
  11. case 'db':
  12. /**
  13. * @var \PDO $db
  14. */
  15. $stmt = $db->prepare('INSERT INTO `roach`(`msg`)VALUES(?)');
  16. $stmt->execute([ $msg ]);
  17. case 'redis':
  18. /**
  19. * @var \Redis $redis
  20. */
  21. $redis->lPush('roach:log', $msg);
  22. default:
  23. file_put_contents('/tmp/roach.log', $msg, FILE_APPEND| LOCK_EX);
  24. }
  25. }

以上我们实现了记录日志的简单基本功能,调用端提供drivermsg参数即可,调用api很简单,log方法里的实现也就用了一个switch,这里有什么问题呢?

以上代码看着很简单,没什么大问题,但是我们考虑一下,是否对修改关闭了,当我们需要修改某一个driver记录日志的细节时,都需要修改log方法,可见没有对修改关闭;再看一下,如果我们需要增加kafka驱动,还是需要修改log方法,可见也不是对扩展开放,那么怎么修改呢?

这里就用到了策略模式,下面是应用策略模式实现一个打日志功能

  1. <?php
  2. /**
  3. * Class LogContext
  4. * @datetime 2020/7/17 5:51 PM
  5. * @author roach
  6. * @email jhq0113@163.com
  7. */
  8. class LogContext
  9. {
  10. /**
  11. * @var ILog
  12. * @datetime 2020/7/17 5:51 PM
  13. * @author roach
  14. * @email jhq0113@163.com
  15. */
  16. private $_driver;
  17. /**
  18. * @param ILog $driver
  19. * @datetime 2020/7/17 5:51 PM
  20. * @author roach
  21. * @email jhq0113@163.com
  22. */
  23. public function setDriver(ILog $driver)
  24. {
  25. $this->_driver = $driver;
  26. }
  27. /**
  28. * @param $msg
  29. * @datetime 2020/7/17 5:52 PM
  30. * @author roach
  31. * @email jhq0113@163.com
  32. */
  33. public function log($msg)
  34. {
  35. $this->_driver->log($msg);
  36. }
  37. }
  38. /**
  39. * Interface ILog
  40. * @datetime 2020/7/17 5:50 PM
  41. * @author roach
  42. * @email jhq0113@163.com
  43. */
  44. interface ILog
  45. {
  46. /**
  47. * @param string $msg
  48. * @return mixed
  49. * @datetime 2020/7/17 5:50 PM
  50. * @author roach
  51. * @email jhq0113@163.com
  52. */
  53. public function log($msg);
  54. }
  55. /**
  56. * Class Redis
  57. * @datetime 2020/7/17 5:52 PM
  58. * @author roach
  59. * @email jhq0113@163.com
  60. */
  61. class Redis implements ILog
  62. {
  63. /**
  64. * @param string $msg
  65. * @return mixed|void
  66. * @datetime 2020/7/17 5:52 PM
  67. * @author roach
  68. * @email jhq0113@163.com
  69. */
  70. public function log($msg)
  71. {
  72. /**
  73. * @var \Redis $redis
  74. */
  75. $redis->lPush('roach:log', $msg);
  76. }
  77. }
  78. /**
  79. * Class File
  80. * @datetime 2020/7/17 5:53 PM
  81. * @author roach
  82. * @email jhq0113@163.com
  83. */
  84. class File implements ILog
  85. {
  86. /**
  87. * @param string $msg
  88. * @return mixed|void
  89. * @datetime 2020/7/17 5:53 PM
  90. * @author roach
  91. * @email jhq0113@163.com
  92. */
  93. public function log($msg)
  94. {
  95. file_put_contents('/tmp/roach.log', $msg, FILE_APPEND| LOCK_EX);
  96. }
  97. }
  98. /**
  99. * Class Db
  100. * @datetime 2020/7/17 5:54 PM
  101. * @author roach
  102. * @email jhq0113@163.com
  103. */
  104. class Db implements ILog
  105. {
  106. /**
  107. * @param string $msg
  108. * @return mixed|void
  109. * @datetime 2020/7/17 5:54 PM
  110. * @author roach
  111. * @email jhq0113@163.com
  112. */
  113. public function log($msg)
  114. {
  115. /**
  116. * @var \PDO $db
  117. */
  118. $stmt = $db->prepare('INSERT INTO `roach`(`msg`)VALUES(?)');
  119. $stmt->execute([ $msg ]);
  120. }
  121. }

以上代码是一个策略模式的实现例程,调用端如果想记录日志,通过调用LogContextlog方法即可,在调用log方法前需要调用setDriver初始化_driver实例。现在我们再来看是否对修改关闭了,当我们想修改文件日志行为,直接修改类File即可,其他的driver不受影响;再看是否对扩展开放,当我们想把日志记录到Kafka里,我们增加Kafka类即可,其他driver不受影响。

关于策略模式,你学会了吗?

QQ群:

姜海强的QQ群

公众号:

360tryst公众号