觀察者模式及php委托

觀察者模式的核心是將一個(gè)中心類(主體)和監(jiān)控中心類的一些觀察者做解耦合。面向?qū)ο笤O(shè)計(jì)核心思想就是面向抽象和接口編程内狸,因此具體對(duì)象間灿里,相互知道的越少越好,這樣發(fā)生改變時(shí)才不至于互相影響俯逾。因此贸桶,對(duì)于觀察者模式來說,目標(biāo)和觀察者不是緊密耦合的桌肴,目標(biāo)所知道的僅僅是它有一系列的觀察者皇筛,而觀察者屬于哪一個(gè)具體類,目標(biāo)是沒必要知道的坠七。

對(duì)于傳統(tǒng)意義上的觀察者模式來說水醋,所有的觀察者類都會(huì)實(shí)現(xiàn)一個(gè)抽象觀察者接口,中心類會(huì)保存一組觀察者對(duì)象的引用彪置,當(dāng)中心類的狀態(tài)發(fā)生改變時(shí)拄踪,調(diào)用notify方法將已保存的觀察者對(duì)象逐個(gè)更新,因?yàn)檫@是一個(gè)循環(huán)遍歷拳魁,所以要求這些觀察者對(duì)象必須有統(tǒng)一的接口惶桐。中心類同時(shí)也會(huì)有添加和移除觀察者對(duì)象的方法寓搬。(調(diào)用代碼見ClientController中的observe方法)

但在實(shí)際使用過程中泽疆,主體和觀察者可能早就已經(jīng)存在了旱爆,他們之間根本就互相不知道店乐,由客戶端來決定通知誰赶舆。如果在C#中澜驮,可以利用委托來實(shí)現(xiàn)漱逸,在php里纳决,可以用魔術(shù)方法來模擬C#里的委托释树。在主體類里增加一個(gè)$eventHandles數(shù)組肠槽,然后在客戶端將觀察者對(duì)象添加到這個(gè)數(shù)組里,這個(gè)時(shí)候相當(dāng)于主體類也神奇的擁有了這些觀察者類的方法奢啥。但這樣做對(duì)于外部世界來說署浩,提供的是一個(gè)動(dòng)態(tài)的接口,沒有辦法進(jìn)行反射扫尺,客戶程序員無法一下子理清頭緒筋栋。因此使用的時(shí)候最好有注釋或文檔提醒。(調(diào)用代碼見ClientController中的observe1方法)

<?php
namespace Basic\Logic;

class Subject
{
    private $observers = [];

    public $eventHandles = [];

    public $subjectName;

    public function __construct($subjectName)
    {
        $this->subjectName = $subjectName . ' notify --';
    }

    public function attach(Observer $observer)
    {
        array_push($this->observers, $observer);
    }

    public function detach(Observer $observer)
    {
        foreach ($this->observers as $k => $v) {
            if ($observer == $v) {
                unset($k);
                break;
            }
        }
    }

    public function notify()
    {
        /** @var Observer $observer */
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }

    public function notify1()
    {
        foreach ($this->eventHandles as $eventHandle) {
            if (method_exists($eventHandle['obj'], $eventHandle['func'])) {
                $eventHandle['obj']->$eventHandle['func']($this);
            }
        }
    }

    public function getState()
    {
        /** @var Observer $observer */
        foreach ($this->observers as $observer) {
            $observer->getState();
        }
    }

    public function __call($methodName, $args)
    {
        foreach ($this->eventHandles as $eventHandle) {
            if (method_exists($eventHandle, $methodName)) {
                $eventHandle->$methodName($this);
            }
        }
    }
}
<?php
namespace Basic\Logic;

abstract class Observer
{
    protected $state;

    abstract public function update(Subject $subject);

    public function getState()
    {
        echo $this->state . "<br>";
    }
}
<?php
namespace Basic\Logic;

class ObserverA extends Observer
{
    protected $state = 'ObserverA';

    public function update(Subject $subject)
    {
        $this->state = $subject->subjectName . 'notify observerA';
        echo $this->state . "<br>";
    }

    public function closeState(Subject $subject)
    {
        $this->state = $subject->subjectName . 'close observerA';
        echo $this->state . "<br>";
    }

}
<?php
namespace Basic\Logic;

class ObserverB extends Observer
{

    protected $state = 'ObserverB';

    public function update(Subject $subject)
    {
        $this->state = $subject->subjectName . 'notify observerB';
        echo $this->state . "<br>";
    }

    public function openState(Subject $subject)
    {
        $this->state = $subject->subjectName . 'open observerB';
        echo $this->state . "<br>";
    }
}

observe2方法是observe1方法的另一種更簡(jiǎn)潔的寫法正驻。這三種寫法各有利弊弊攘,具體的實(shí)現(xiàn)需要根據(jù)真實(shí)的環(huán)境來做出選擇抢腐。

<?php
namespace Basic\Controller;

use Basic\Logic\ObserverA;
use Basic\Logic\ObserverB;
use Basic\Logic\Subject;

class ClientController
{
    public function observe()
    {
        $subject = new Subject('subjectB');
        $subject->attach(new ObserverA());
        $subject->attach(new ObserverB());
        $subject->notify();
    }

    public function observe1()
    {
        $subject = new Subject('subjectB');
        $subject->eventHandles[] = new ObserverA();
        $subject->eventHandles[] = new ObserverB();
        $subject->closeState();
        $subject->openState();
    }

    public function observe2()
    {
        $subject = new Subject('subjectB');
        $subject->eventHandles[] = [
            'obj'  => new ObserverA(),
            'func' => 'closeState'
        ];
        $subject->eventHandles[] = [
            'obj'  => new ObserverB(),
            'func' => 'openState'
        ];
        $subject->notify1();
    }
}

版權(quán)聲明:本文為原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處襟交,謝謝~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末迈倍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子捣域,更是在濱河造成了極大的恐慌啼染,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,946評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件焕梅,死亡現(xiàn)場(chǎng)離奇詭異迹鹅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)贞言,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門斜棚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人该窗,你說我怎么就攤上這事弟蚀。” “怎么了酗失?”我有些...
    開封第一講書人閱讀 169,716評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵义钉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我规肴,道長(zhǎng)捶闸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,222評(píng)論 1 300
  • 正文 為了忘掉前任奏纪,我火速辦了婚禮,結(jié)果婚禮上斩启,老公的妹妹穿的比我還像新娘序调。我一直安慰自己,他們只是感情好兔簇,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評(píng)論 6 398
  • 文/花漫 我一把揭開白布发绢。 她就那樣靜靜地躺著,像睡著了一般垄琐。 火紅的嫁衣襯著肌膚如雪边酒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,807評(píng)論 1 314
  • 那天狸窘,我揣著相機(jī)與錄音墩朦,去河邊找鬼。 笑死翻擒,一個(gè)胖子當(dāng)著我的面吹牛氓涣,可吹牛的內(nèi)容都是我干的牛哺。 我是一名探鬼主播,決...
    沈念sama閱讀 41,235評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼劳吠,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼引润!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起痒玩,我...
    開封第一講書人閱讀 40,189評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤淳附,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蠢古,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奴曙,經(jīng)...
    沈念sama閱讀 46,712評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評(píng)論 3 343
  • 正文 我和宋清朗相戀三年便瑟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缆毁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,926評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡到涂,死狀恐怖脊框,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情践啄,我是刑警寧澤浇雹,帶...
    沈念sama閱讀 36,580評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站屿讽,受9級(jí)特大地震影響昭灵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜伐谈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評(píng)論 3 336
  • 文/蒙蒙 一烂完、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧诵棵,春花似錦抠蚣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至距贷,卻和暖如春柄冲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背忠蝗。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工现横, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,368評(píng)論 3 379
  • 正文 我出身青樓长赞,卻偏偏與公主長(zhǎng)得像晦攒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子得哆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容