一说到这个模式,就不得不提循环语句。在《大话设计模式》中,作者说道这个模式当初的学习意义更大于实际意义,这是为什么呢?当然就是被foreach这货给整得。任何语言都有这种相似的语法能够方便快捷的对数组、对象进行遍历,从而让迭代器模式从居高临下的23大设计模式中的明星缓缓成为了路人。特地是咱们这门PHP语言,PHP的弱小之处就在于对于数组的灵便操作,自身就是hashmap的构造,天然会有各种不便的数组操作语法,而foreach也是咱们最罕用的语句,甚至比for还罕用。
Gof类图及解释
GoF定义:提供一种办法程序拜访一个聚合对象中各个元素,而又不需裸露该对象的外部示意
GoF类图
代码实现
interface Aggregate
{
public function CreateIterator();
}
class ConcreteAggregate implements Aggregate
{
public function CreateIterator()
{
$list = [
"a",
"b",
"c",
"d",
];
return new ConcreteIterator($list);
}
}
首先是聚合类,也就是能够进行迭代的类,这里因为我是面向对象的设计模式,所以迭代器模式针对的是对一个类的内容进行迭代。在这里,其实咱们也只是模仿了一个数组交给了迭代器。
interface MyIterator
{
public function First();
public function Next();
public function IsDone();
public function CurrentItem();
}
class ConcreteIterator implements MyIterator
{
private $list;
private $index;
public function __construct($list)
{
$this->list = $list;
$this->index = 0;
}
public function First()
{
$this->index = 0;
}
public function Next()
{
$this->index++;
}
public function IsDone()
{
return $this->index >= count($this->list);
}
public function CurrentItem()
{
return $this->list[$this->index];
}
}
迭代器闪亮退场,次要实现了四个办法来对汇合数据进行操作。有点像学习数据结构或数据库时对游标进行的操作。用First()和Next()来挪动游标,用CurrentItem()来取得以后游标的数据内容,用IsDone()来确认是否还有下一条数据。所以,这个模式也另称为游标模式。
$agreegate = new ConcreteAggregate();
$iterator = $agreegate->CreateIterator();
while (!$iterator->IsDone()) {
echo $iterator->CurrentItem(), PHP_EOL;
$iterator->Next();
}
客户端间接应用while来进行操作即可。
- 大家肯定很好奇,为什么咱们的迭代器接口类不必Iterator来命名?试试就晓得,PHP为咱们筹备好了一个这个接口,实现之后就能够用foreach来应用这个实现了Iterator接口的类了,是不是很高大上。咱们最初再看这个类的应用。
- 不是说好对类进行遍历吗?为啥来回传递一个数组?开发过Java的同学肯定晓得,在一个名为Object类的JavaBean中,会写一个变量List<Object>类型的变量如List<Object> myList,用来示意以后对象的汇合。在应用的时候给这个List增加数据后,下次就能够间接用Object.myList来取得一组数据了。比方从接口中取得的json数组内容就能够这样存在一个Bean中。这时,咱们应用迭代器就能够只针对本人这个对象外部的这个数组来进行操作啦!
- 上述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
<?php
interface MsgIterator
{
public function First();
public function Next();
public function IsDone();
public function CurrentItem();
}
// 正向迭代器
class MsgIteratorAsc implements MsgIterator
{
private $list;
private $index;
public function __construct($list)
{
$this->list = $list;
$this->index = 0;
}
public function First()
{
$this->index = 0;
}
public function Next()
{
$this->index++;
}
public function IsDone()
{
return $this->index >= count($this->list);
}
public function CurrentItem()
{
return $this->list[$this->index];
}
}
// 反向迭代器
class MsgIteratorDesc implements MsgIterator
{
private $list;
private $index;
public function __construct($list)
{
// 反转数组
$this->list = array_reverse($list);
$this->index = 0;
}
public function First()
{
$this->index = 0;
}
public function Next()
{
$this->index++;
}
public function IsDone()
{
return $this->index >= count($this->list);
}
public function CurrentItem()
{
return $this->list[$this->index];
}
}
interface Message
{
public function CreateIterator($list);
}
class MessageAsc implements Message
{
public function CreateIterator($list)
{
return new MsgIteratorAsc($list);
}
}
class MessageDesc implements Message
{
public function CreateIterator($list)
{
return new MsgIteratorDesc($list);
}
}
// 要发的短信号码列表
$mobileList = [
'13111111111',
'13111111112',
'13111111113',
'13111111114',
'13111111115',
'13111111116',
'13111111117',
'13111111118',
];
// A服务器脚本或应用swoole发送正向的一半
$serverA = new MessageAsc();
$iteratorA = $serverA->CreateIterator($mobileList);
while (!$iteratorA->IsDone()) {
echo $iteratorA->CurrentItem(), PHP_EOL;
$iteratorA->Next();
}
// B服务器脚本或应用swoole同步发送反向的一半
$serverB = new MessageDesc();
$iteratorB = $serverB->CreateIterator($mobileList);
while (!$iteratorB->IsDone()) {
echo $iteratorB->CurrentItem(), PHP_EOL;
$iteratorB->Next();
}
阐明
- 其实就是两个迭代器,一个是正序一个是倒序,而后遍历数组
- 例子中咱们还是对一个数组的操作,另外用两个相似于工厂办法模式的类来对迭代器进行封装
- 例子非常简单,但有时候这种用法也十分实用,比方一些搜索引擎排名的爬虫,屡次确认某些关键词的排名,这时候咱们就能够正着、反着来回进行验证
残缺源码: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自身的扩大库居然为咱们筹备了很多接口。平时写代码的时候是不是能够炫炫技了呢!!别急,咱们进入设计模式的世界并不久,还有很多有意思的设计模式等着咱们去学习,就像原型模式,这货干嘛的?复制本人哦,克隆人的和平!
各自媒体平台均可搜寻【硬核项目经理】
发表回复