关于php:PHP设计模式之迭代器模式

38次阅读

共计 4858 个字符,预计需要花费 13 分钟才能阅读完成。

一说到这个模式,就不得不提循环语句。在《大话设计模式》中,作者说道这个模式当初的学习意义更大于实际意义,这是为什么呢?当然就是被 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 自身的扩大库居然为咱们筹备了很多接口。平时写代码的时候是不是能够炫炫技了呢!!别急,咱们进入设计模式的世界并不久,还有很多有意思的设计模式等着咱们去学习,就像 原型模式,这货干嘛的?复制本人哦,克隆人的和平!

各自媒体平台均可搜寻【硬核项目经理】

正文完
 0