行為模式(觀察者模式)

2021-09-21 17:36:18 字數 3622 閱讀 3243

觀察者模式,也稱發布-訂閱模式,定義了乙個被觀察者和多個觀察者的、一對多的物件關係。

在被觀察者狀態發生變化的時候,它的所有觀察者都會收到通知,並自動更新。

觀察者模式通常用在實時事件處理系統、元件間解耦、資料庫驅動的訊息佇列系統,同時也是mvc設計模式中的重要組成部分

以下我們以訂單建立為例。

當訂單建立後,系統會傳送郵件簡訊,並儲存日誌記錄

在沒有用觀察者模式的時候,如下:

class order

}

**中,在order類中呼叫各類的方法來實現通知。當在客戶端建立訂單:

$order = new order();

$order->addorder();

就會同時產生三個通知:傳送郵件、傳送簡訊和記錄日誌。

在系統小的時候,這是非常快捷有效的方式。

可是,當系統變大的時候,這種方法馬上面臨難以擴充套件的問題,並且容易出錯:

如果訂單不需要某種通知,比如不需要記錄日誌,則必須修改order類,做狀態的判斷;

如果再加一種通知方式,如系統訊息通知,則除了增加新類,同時還需要修改order類和客戶端。

這兩條都不符合物件導向中的開閉原則,會讓系統越來越難維護。

接下來我們用觀察者模式解決這個問題。

別的功能會依賴於它們的狀態進行各種動作。

/**

* 被觀察者介面

*/inte***ce observable

/** * 被觀察者

* 職責:新增觀察者到$observers屬性中,

* 有變動時通過notify()方法執行通知

*/class order implements observable

}// 移除觀察者

public function detach(observer $observer)

}// 遍歷呼叫觀察者的update()方法進行通知,不關心其具體實現方式

public function notify()

}// 訂單狀態有變化時傳送通知

public function addorder()

// 獲取提供給觀察者的狀態

public function getstate()

}

被觀察者至少要實現attach()detach()notify()三個方法,用以新增、刪除和通知觀察者。

通知的方式是,在類中的其他方法(如:建立訂單)呼叫notify()方法。

另外,觀察者可能用到被觀察者的一些狀態資訊。

所以,要在notify()中把當前物件作為引數傳給觀察者,方便其通過提供的public方法獲得被觀察者的狀態資訊。

本例用getstate()方法供給觀察者獲取狀態資訊。

觀察者可能有多個,但每個觀察者都必須實現observer介面規定的update()方法,這是接收被觀察者通知的唯一渠道。

/**

* 觀察者介面

*/inte***ce observer

/** * 觀察者1:傳送郵件

*/class email implements observer

else

}}/**

* 觀察者2:簡訊通知

*/class message implements observer

else

}}/**

* 觀察者3:記錄日誌

*/class log implements observer

}

這裡有三個觀察者:傳送郵件簡訊通知記錄日誌,它們都實現了update()方法。

其中,傳送郵件和簡訊依賴於訂單、也就是被觀察者的狀態,來決定傳送訊息的內容,記錄日誌則不需要訂單的狀態。

然後我們建立乙個客戶端,內容:

// 建立觀察者物件

$email = new email();

$message = new message();

$log = new log();

// 建立訂單物件

$order = new order();

// 向訂單物件中註冊3個觀察者:傳送郵件、簡訊通知、記錄日誌

$order->attach($email);

$order->attach($message);

$order->attach($log);

// 新增訂單,新增時會自動傳送通知給觀察者

$order->addorder();

echo '

';// 刪除記錄日誌觀察者

$order->detach($log);

// 新增另乙個訂單,會再次傳送通知給觀察著

$order->addorder();

執行應用後,會輸出這樣的訊息:

傳送郵件:您已經成功下單。新增日誌:生成了乙個訂單記錄。系統訊息:您已下單成功。

傳送郵件:您已經成功下單。新增日誌:生成了乙個訂單記錄。

對於不需要通知的觀察者,用detach()移出觀察者列表即可。

這種情況就解開了類之間的耦合。

如果再需要新增乙個觀察者,如下,只需要新增觀察者類本身,實現update()方法。

/**

* 觀察者4:系統訊息

*/class alert implements observer

}

再到客戶端中註冊alert類到觀察者列表中:

// 建立「系統訊息」觀察者

$alert = new alert();

// 註冊觀察者到訂單物件中

$order->attach($alert);

就能訂閱被觀察者的通知。

在觀察者模式中,被觀察者完全不需要關心觀察者,在自身狀態有變化是,遍歷執行觀察者update()方法即完成通知。

在觀察者模式中,被觀察者通過新增attach()方法,提供給觀察者註冊,使自己變得可見。

當被觀察者改變時,給註冊的觀察者傳送通知。至於觀察者如何處理通知,被觀察者不需要關心。

這是一種良好的設計,物件之間不必相互理解,同樣能夠相互通訊。

uml如下:

物件導向程式設計中,任何物件的狀態都非常重要,它們是物件間互動的橋梁。

當乙個物件的改變需要被其他物件關注時,觀察者模式就派上用場了。

行為模式 觀察者 模式

觀察者模式應用比較廣泛,又被稱為 發布 訂閱 模式。它用來定義物件間一種一對多的依賴關係,當乙個物件的狀態發生變化時,所有依賴它的物件都得到通知並被自動更新。觀察者模式的角色有 抽象主題 具體主題 發布者 抽象觀察者和具體觀察者 訂閱者 from abc import abcmeta,abstrac...

觀察者模式 行為

當物件間存在一對多關係時,則使用觀察者模式 observer pattern 比如,當乙個物件被修改時,則會自動通知依賴它的物件。觀察者模式屬於行為型模式。意圖 定義物件間的一種一對多的依賴關係,當乙個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。主要解決 乙個物件狀態改變給其他物...

行為型模式 觀察者模式

物件間的一種一對多的依賴關係,當乙個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。subject 抽象的主題,被觀察的物件,提供 attach 和detach observer 物件的介面。concretesubject 具體的被觀察物件,維持 concretesubject 狀態...