觀察者模式的核心是將一個(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)注明出處襟交,謝謝~~