iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 27
1

本文同步更新於blog

情境:讓我們用Line群組,來實作觀察者模式

  • 首先實作抽象的觀察者類別 (Observer)

其中會有接收到主題類別通知時的更新方法 (具體實作內容由子類決定)。

<?php

namespace App\ObserverPattern\LineGroup;

abstract class Observer
{
    abstract public function update();
}
  • 接著實作抽象的主題類別 (Subject)

它會有新增觀察者移除觀察者通知觀察者的方法。

<?php

namespace App\ObserverPattern\LineGroup;

use App\ObserverPattern\LineGroup\Observer;

abstract class Subject
{
    /**
     * @var array
     */
    protected $observers = [];

    public function attachObserver(Observer $observer)
    {
        $this->observers[] = $observer;
    }

    public function detachObserver(Observer $observer)
    {
        $index = array_search($observer, $this->observers);

        if ($index >= 0) {
            unset($this->observers[$index]);
        }
    }

    public function notifyObservers()
    {
        foreach ($this->observers as $observer) {
            $observer->update();
        }
    }
}

  • 利用剛剛建立的觀察者類別,實作使用者
<?php

namespace App\ObserverPattern\LineGroup;

use App\ObserverPattern\LineGroup\Observer;

class User extends Observer
{
    protected $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function update()
    {
        //使用者手機跳出通知
        //使用者電腦跳出通知
    }
}

  • 實作群組聊天室,並模擬使用情況
<?php

namespace App\ObserverPattern\LineGroup;

use App\ObserverPattern\LineGroup\Subject;
use App\ObserverPattern\LineGroup\User;

class Program extends Subject
{
    protected $state = 'nothing new';

    public function run()
    {
        //Bear加入群組
        $bear = new User('Bear');
        $this->attachObserver($bear);

        //通知群組
        $this->notifyObservers();

        //Jane加入群組
        $jane = new User('Jane');
        $this->attachObserver($jane);

        //通知群組
        $this->notifyObservers();

        //有新訊息,通知群組
        $this->state = 'new message';
        $this->notifyObservers();
        $this->state = 'nothing new';

        //Jane離開群組
        $this->detachObserver($jane);

        //通知群組
        $this->notifyObservers();
    }
}


[單一職責原則]
我們將主題類別 (Subject)觀察者類別 (Observer) 視作兩種不同的職責。
目前範例尚未將聊天室的職責通知的職責分離。

[開放封閉原則]
當新增新的主題類別時,我們可以輕易地新增、移除、通知對應觀察者。
亦可以新增新的觀察者類別,再將其加入既有的主題類別。

[里氏替換原則]
透過子類來定義觀察者類別中更新方法具體的實作。
目前範例的缺點是,觀察者類別不好對更新方法取更適合的命名

[依賴反轉原則]
抽象主題類別依賴於抽象的觀察者類別。
使用者類別實作抽象的觀察者類別。

主題類別不必知道具體觀察者想做什麼,
僅需知道觀察者類別有接口可以通知更新。


最後附上類別圖:
https://ithelp.ithome.com.tw/upload/images/20201012/20111630Q892DiTT4B.png
(註:若不熟悉 UML 類別圖,可參考UML類別圖說明。)

ʕ •ᴥ•ʔ:架構容易,細節仍需琢磨的模式。


上一篇
Day26. 觀察者模式
下一篇
Day28. 抽象工廠模式
系列文
你終究都要學設計模式的,那為什麼不一開始就學呢?57
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言