经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » PHP » 查看文章
PHP设计模式之迭代器模式
来源:cnblogs  作者:硬核项目经理  时间:2020/12/21 15:14:26  对本文有异议

一说到这个模式,就不得不提循环语句。在《大话设计模式》中,作者说道这个模式现在的学习意义更大于实际意义,这是为什么呢?当然就是被foreach这货给整得。任何语言都有这种类似的语法可以方便快捷的对数组、对象进行遍历,从而让迭代器模式从高高在上的23大设计模式中的明星慢慢成为了路人。特别是我们这门PHP语言,PHP的强大之处就在于对于数组的灵活操作,本身就是hashmap的结构,自然会有各种方便的数组操作语法,而foreach也是我们最常用的语句,甚至比for还常用。

Gof类图及解释

GoF定义:提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示

GoF类图

迭代器模式

代码实现

  1. interface Aggregate
  2. {
  3. public function CreateIterator();
  4. }
  5. class ConcreteAggregate implements Aggregate
  6. {
  7. public function CreateIterator()
  8. {
  9. $list = [
  10. "a",
  11. "b",
  12. "c",
  13. "d",
  14. ];
  15. return new ConcreteIterator($list);
  16. }
  17. }

首先是聚合类,也就是可以进行迭代的类,这里因为我是面向对象的设计模式,所以迭代器模式针对的是对一个类的内容进行迭代。在这里,其实我们也只是模拟了一个数组交给了迭代器。

  1. interface MyIterator
  2. {
  3. public function First();
  4. public function Next();
  5. public function IsDone();
  6. public function CurrentItem();
  7. }
  8. class ConcreteIterator implements MyIterator
  9. {
  10. private $list;
  11. private $index;
  12. public function __construct($list)
  13. {
  14. $this->list = $list;
  15. $this->index = 0;
  16. }
  17. public function First()
  18. {
  19. $this->index = 0;
  20. }
  21. public function Next()
  22. {
  23. $this->index++;
  24. }
  25. public function IsDone()
  26. {
  27. return $this->index >= count($this->list);
  28. }
  29. public function CurrentItem()
  30. {
  31. return $this->list[$this->index];
  32. }
  33. }

迭代器闪亮登场,主要实现了四个方法来对集合数据进行操作。有点像学习数据结构或数据库时对游标进行的操作。用First()和Next()来移动游标,用CurrentItem()来获得当前游标的数据内容,用IsDone()来确认是否还有下一条数据。所以,这个模式也另称为游标模式

  1. $agreegate = new ConcreteAggregate();
  2. $iterator = $agreegate->CreateIterator();
  3. while (!$iterator->IsDone()) {
  4. echo $iterator->CurrentItem(), PHP_EOL;
  5. $iterator->Next();
  6. }

客户端直接使用while来进行操作即可。

  • 大家一定很好奇,为什么我们的迭代器接口类不用Iterator来命名?试试就知道,PHP为我们准备好了一个这个接口,实现之后就可以用foreach来使用这个实现了Iterator接口的类了,是不是很高大上。我们最后再看这个类的使用。
  • 不是说好对类进行遍历吗?为啥来回传递一个数组?开发过Java的同学一定知道,在一个名为Object类的JavaBean中,会写一个变量List
  • 上述Java的内容其实是笔者在做Android开发时经常会用到的,有时数据库的JavaBean也会出现这种数组来存储外键。但在PHP中一般很少使用,因为PHP中大部分的AR对象和Java中的Bean概念还是略有不同。有兴趣的同学可以了解下!

我们的手机工厂不得了,自己组装了一条生产线,这条生产线主要是做什么的呢?成型机我们已经交给富X康来搞定了,我们这条线就是给手机刷颜色的。当我们把所有已经交货的手机(Aggregate)放到不同的生产线后(Iterator),就会一台一台的帮我们刷上当前生产线的颜色,是不是很强大!!科技不止于换壳,这条线还在,我们就可以再做别的事儿,比如加点挂绳什么的,反正只要能一台一台的通过我就能装上东西,你说好用不好用!!

完整代码:https://github.com/zhangyue0503/designpatterns-php/blob/master/07.iterator/source/iterator.php

实例

实例还是围绕着我们的短信发送来看。这一次,我们的业务需求是尽快的发一批通知短信给用户,因为活动的时候可不等人啊。在之前我们会使用多个脚本来把用户手机号分成多组来进行发送。现在我们可以用swoole来直接多线程的发送。所要达到的效果其实就是为了快速的把成百上千的短信发完。这个时候我们也会做一些策略,比如数据库里是100条要送的短信,有个字段是发送状态,一个线程正序的发,一个线程倒序的发,当正序和倒序都发送到50条的时候其实已经同步的发完这100条了,不过也有可能会有失败的情况出现,这时,两个线程还会继续去发送那些上次发送不成功的信息,这样能够最大程度的确保发送的效率和到达率。

消息发送迭代器类图

消息发送迭代器

完整源码:https://github.com/zhangyue0503/designpatterns-php/blob/master/07.iterator/source/iterator-msg.php

  1. <?php
  2. interface MsgIterator
  3. {
  4. public function First();
  5. public function Next();
  6. public function IsDone();
  7. public function CurrentItem();
  8. }
  9. // 正向迭代器
  10. class MsgIteratorAsc implements MsgIterator
  11. {
  12. private $list;
  13. private $index;
  14. public function __construct($list)
  15. {
  16. $this->list = $list;
  17. $this->index = 0;
  18. }
  19. public function First()
  20. {
  21. $this->index = 0;
  22. }
  23. public function Next()
  24. {
  25. $this->index++;
  26. }
  27. public function IsDone()
  28. {
  29. return $this->index >= count($this->list);
  30. }
  31. public function CurrentItem()
  32. {
  33. return $this->list[$this->index];
  34. }
  35. }
  36. // 反向迭代器
  37. class MsgIteratorDesc implements MsgIterator
  38. {
  39. private $list;
  40. private $index;
  41. public function __construct($list)
  42. {
  43. // 反转数组
  44. $this->list = array_reverse($list);
  45. $this->index = 0;
  46. }
  47. public function First()
  48. {
  49. $this->index = 0;
  50. }
  51. public function Next()
  52. {
  53. $this->index++;
  54. }
  55. public function IsDone()
  56. {
  57. return $this->index >= count($this->list);
  58. }
  59. public function CurrentItem()
  60. {
  61. return $this->list[$this->index];
  62. }
  63. }
  64. interface Message
  65. {
  66. public function CreateIterator($list);
  67. }
  68. class MessageAsc implements Message
  69. {
  70. public function CreateIterator($list)
  71. {
  72. return new MsgIteratorAsc($list);
  73. }
  74. }
  75. class MessageDesc implements Message
  76. {
  77. public function CreateIterator($list)
  78. {
  79. return new MsgIteratorDesc($list);
  80. }
  81. }
  82. // 要发的短信号码列表
  83. $mobileList = [
  84. '13111111111',
  85. '13111111112',
  86. '13111111113',
  87. '13111111114',
  88. '13111111115',
  89. '13111111116',
  90. '13111111117',
  91. '13111111118',
  92. ];
  93. // A服务器脚本或使用swoole发送正向的一半
  94. $serverA = new MessageAsc();
  95. $iteratorA = $serverA->CreateIterator($mobileList);
  96. while (!$iteratorA->IsDone()) {
  97. echo $iteratorA->CurrentItem(), PHP_EOL;
  98. $iteratorA->Next();
  99. }
  100. // B服务器脚本或使用swoole同步发送反向的一半
  101. $serverB = new MessageDesc();
  102. $iteratorB = $serverB->CreateIterator($mobileList);
  103. while (!$iteratorB->IsDone()) {
  104. echo $iteratorB->CurrentItem(), PHP_EOL;
  105. $iteratorB->Next();
  106. }

说明

  • 其实就是两个迭代器,一个是正序一个是倒序,然后遍历数组
  • 例子中我们还是对一个数组的操作,另外用两个类似于工厂方法模式的类来对迭代器进行封装
  • 例子非常简单,但有时候这种用法也非常实用,比如一些搜索引擎排名的爬虫,多次确认某些关键词的排名,这时候我们就可以正着、反着来回进行验证

完整源码:https://github.com/zhangyue0503/designpatterns-php/blob/master/06.observer/source/spl_observer.php

彩蛋

PHP中的Iterator接口已经为我们准备好了一套标准的Iterator模式的实现,而且(这里需要画重点),实现这个接口的类可以用foreach来遍历哦!

文档:https://www.php.net/manual/zh/class.iterator.php

源码:https://github.com/zhangyue0503/designpatterns-php/blob/master/07.iterator/source/iterator-php.php

文档中相关的接口都可以看看,更重要的是,PHP的SPL扩展中,也为我们准备了很多常用的迭代器封装。要知道,面试的时候要是能说出这里面的几个来,那面试官可是也会刮目相看的哦!

SPL迭代器:https://www.php.net/manual/zh/spl.iterators.php

下期看点

迭代器很好玩吧,而且和观察者一样,PHP本身的扩展库竟然为我们准备了很多接口。平常写代码的时候是不是可以炫炫技了呢!!别急,我们进入设计模式的世界并不久,还有很多有意思的设计模式等着我们去学习,就像原型模式,这货干嘛的?复制自己哦,克隆人的战争!

关注公众号:【硬核项目经理】获取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料

知乎、公众号、抖音、头条搜索【硬核项目经理】

B站ID:482780532

原文链接:http://www.cnblogs.com/zyblog-coder/p/14147869.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号