PHP設計模式之迭代器模式

一說到這個模式,就不得不提循環語句。在《大話設計模式》中,做者說道這個模式如今的學習意義更大於實際意義,這是爲何呢?固然就是被foreach這貨給整得。任何語言都有這種相似的語法能夠方便快捷的對數組、對象進行遍歷,從而讓迭代器模式從高高在上的23大設計模式中的明星慢慢成爲了路人。特別是咱們這門PHP語言,PHP的強大之處就在於對於數組的靈活操做,自己就是hashmap的結構,天然會有各類方便的數組操做語法,而foreach也是咱們最經常使用的語句,甚至比for還經常使用。php

Gof類圖及解釋

GoF定義:提供一種方法順序訪問一個聚合對象中各個元素,而又不需暴露該對象的內部表示git

GoF類圖github

迭代器模式

代碼實現面試

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
  • 上述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條了,不過也有可能會有失敗的狀況出現,這時,兩個線程還會繼續去發送那些上次發送不成功的信息,這樣可以最大程度的確保發送的效率和到達率。swoole

消息發送迭代器類圖

消息發送迭代器

完整源碼: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自己的擴展庫居然爲咱們準備了不少接口。日常寫代碼的時候是否是能夠炫炫技了呢!!別急,咱們進入設計模式的世界並不久,還有不少有意思的設計模式等着咱們去學習,就像原型模式,這貨幹嗎的?複製本身哦,克隆人的戰爭!

關注公衆號:【硬核項目經理】獲取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免費得PHP、項目管理學習資料

知乎、公衆號、抖音、頭條搜索【硬核項目經理】

B站ID:482780532

相關文章
相關標籤/搜索