國(guó)外哪個(gè)網(wǎng)站做服裝百度怎么免費(fèi)推廣
設(shè)計(jì)模式 —— 觀察者模式
- 什么是觀察者模式
- 觀察者模式定義
- 觀察者模式的角色
- 觀察者模式的使用場(chǎng)景
- 觀察者模式的實(shí)現(xiàn)
- 被觀察者(Subject)
- 觀察者(Observer)
- 通知(notify)
- 更新顯示(update)
- 觀察者模式的優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn)
- 缺點(diǎn)
我們今天來(lái)介紹觀察者模式:
什么是觀察者模式
觀察者模式定義
觀察者模式(Observer Pattern)是一種行為型設(shè)計(jì)模式,它定義了對(duì)象間的一對(duì)多依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生變化時(shí),所有依賴于它的對(duì)象都會(huì)自動(dòng)收到通知并更新。在這種模式中,一個(gè)目標(biāo)對(duì)象(被觀察對(duì)象)管理所有相依于它的觀察者對(duì)象,并在其狀態(tài)改變時(shí)主動(dòng)發(fā)出通知。觀察者模式通常被用來(lái)實(shí)現(xiàn)事件處理系統(tǒng).
觀察者模式的角色
觀察者模式涉及以下幾個(gè)核心角色:
- 主題(Subject):也稱為被觀察者或可觀察者,它是具有狀態(tài)的對(duì)象,并維護(hù)著一個(gè)觀察者列表。主題提供了添加、刪除和通知觀察者的方法.
- 觀察者(Observer):觀察者是接收主題通知的對(duì)象。觀察者需要實(shí)現(xiàn)一個(gè)更新方法,當(dāng)收到主題的通知時(shí),調(diào)用該方法進(jìn)行更新操作.
- 具體主題(Concrete Subject):具體主題是主題的具體實(shí)現(xiàn)類。它維護(hù)著觀察者列表,并在狀態(tài)發(fā)生改變時(shí)通知觀察者.
- 具體觀察者(Concrete Observer):具體觀察者是觀察者的具體實(shí)施類。它實(shí)現(xiàn)了更新方法,定義了在收到主題通知時(shí)需要執(zhí)行的具體操作.
觀察者模式的使用場(chǎng)景
觀察者模式適用于以下場(chǎng)景:
- 當(dāng)一個(gè)抽象模型有兩個(gè)方面,其中一個(gè)方面依賴于另一個(gè)方面。將這兩者封裝在獨(dú)立的對(duì)象中以使它們可以各自獨(dú)立地改變和復(fù)用.
- 當(dāng)對(duì)一個(gè)對(duì)象的改變需要同時(shí)改變其他對(duì)象,而不知道具體有多少對(duì)象需要被改變.
- 當(dāng)一個(gè)對(duì)象必須通知其他對(duì)象,而它又不能假定其他對(duì)象是誰(shuí).
缺點(diǎn):
-
在應(yīng)用觀察者模式時(shí)需要考慮一些開發(fā)小路問題,程序中包括一個(gè)被觀察者和多個(gè)被觀察者,開發(fā)和調(diào)試比較復(fù)雜.
-
在Java中的消息的通知默認(rèn)是順序執(zhí)行的,一個(gè)觀察者的卡頓會(huì)影響整體的執(zhí)行效率。在這種情況下,一般考慮采用異步的方式.
觀察者模式的實(shí)現(xiàn)
實(shí)現(xiàn)觀察者模式有多種形式,一種直觀的方式是使用“注冊(cè)—通知—撤銷注冊(cè)”的形式。觀察者將自己注冊(cè)到被觀察對(duì)象中,被觀察對(duì)象將觀察者存放在一個(gè)容器里。當(dāng)被觀察對(duì)象發(fā)生了某種變化,它從容器中得到所有注冊(cè)過的觀察者,將變化通知觀察者。觀察者告訴被觀察對(duì)象要撤銷觀察,被觀察對(duì)象從容器中將觀察者去除.
我們舉個(gè)例子:玩家攻擊怪獸掉血顯示血量,增加氣勢(shì)
被觀察者(Subject)
怪獸(或其血量管理類)扮演“被觀察者(Subject)”角色,負(fù)責(zé)維持血量狀態(tài)并管理觀察者列表。
// 定義被觀察者接口,任何能夠被觀察的狀態(tài)持有者(如怪物)需要實(shí)現(xiàn)這個(gè)接口
class Subject {
public:// 虛析構(gòu)函數(shù),確保通過基類指針刪除子類對(duì)象時(shí)能正確調(diào)用子類析構(gòu)函數(shù)virtual ~Subject() {}// attach: 注冊(cè)觀察者到被觀察者,使其可以接收狀態(tài)變更通知virtual void attach(Observer* observer) = 0;// detach: 解注冊(cè)觀察者,不再接收狀態(tài)變更通知virtual void detach(Observer* observer) = 0;// notify: 通知所有觀察者血量變化virtual void notify(int health) = 0;// notifyMoraleChange: 通知所有觀察者氣勢(shì)變化virtual void notifyMoraleChange() = 0;
};// 怪物類,繼承自被觀察者接口,表示它是可被觀察的狀態(tài)持有者
class Monster : public Subject {
public:// 構(gòu)造函數(shù),初始化怪物的血量為10Monster() : _health(100), _morel(0) {}// 析構(gòu)函數(shù),清理資源,雖然當(dāng)前版本未直接管理額外資源,但保持以備未來(lái)擴(kuò)展~Monster() {}private:// _health: 怪物的當(dāng)前血量int _health;// _morel: 怪物的當(dāng)前氣勢(shì)值int _morale;// _observers: 存儲(chǔ)所有觀察怪物狀態(tài)的觀察者指針集合std::vector<Observer*> _observers;
};
觀察者(Observer)
UI顯示組件作為“觀察者(Observer)”,訂閱怪獸的血量變化。
// 定義觀察者接口,任何想要監(jiān)聽怪物狀態(tài)變化的實(shí)體都需要實(shí)現(xiàn)這個(gè)接口
class Monster : public Subject
public:// updateHealthy: 當(dāng)怪物血量發(fā)生變化時(shí),觀察者會(huì)被通知virtual void updateHealthy(int health) = 0;// updateMorale: 當(dāng)怪物氣勢(shì)發(fā)生變化時(shí),觀察者會(huì)被通知virtual void updateMorale(int morale) = 0;
};
通知(notify)
當(dāng)玩家的攻擊導(dǎo)致怪獸血量減少時(shí),怪獸對(duì)象通知所有觀察者(即UI組件)。
// 通知所有觀察者血量變化,調(diào)用觀察者的 updateHealthy 方法。void notifyHeath(int health) override {for(auto & observer: _observers) {observer->updateHealthy(health); // 應(yīng)修正參數(shù)傳遞,確保觀察者獲得實(shí)際的血量值。}}// 通知所有觀察者氣勢(shì)變化,調(diào)用觀察者的 updateMorel 方法。void notifyMoraleChange() override {for(auto & observer: _observers) {observer->updateMorel(_morale); // 同樣,傳遞當(dāng)前氣勢(shì)值給觀察者。}}void takeDamage(int damage){_health -= damage;if (_health < 0) _health = 0;_morale += 20; // 氣勢(shì)增加notifyHeath(_health); // 通知血量變化notifyMoraleChange(); // 新增:通知?dú)鈩?shì)變化}
更新顯示(update)
觀察者收到通知后,各自更新顯示的血量信息。
//屬性條
class Classbuff : public Observer
{
public:void updateHealthy(int health) override{std::cout << "Health Bar Update: Current HP is " << health << std::endl;}void updateMorel(int morale) override{std::cout << "Morale Update: Current Morale is " << morale << std::endl;}
};
完整代碼如下:
// 使用#pragma once防止頭文件重復(fù)包含
#pragma once// 引入所需的標(biāo)準(zhǔn)庫(kù)
#include<iostream>
#include<vector>// **觀察者類定義**
// 觀察者接口,任何觀察怪物狀態(tài)的類需要實(shí)現(xiàn)這兩個(gè)更新方法
class Observer {
public:// 純虛函數(shù),更新血量virtual void updateHealthy(int health) = 0;// 純虛函數(shù),更新氣勢(shì)virtual void updateMorel(int morale) = 0;
};// **被觀察者接口定義**
// 定義被觀察者需要實(shí)現(xiàn)的接口,用于管理觀察者列表及通知狀態(tài)變化
class Subject {
public:// 虛析構(gòu)函數(shù),確保通過基類指針可以安全刪除子類對(duì)象virtual ~Subject() {}// 接口方法,注冊(cè)觀察者virtual void attach(Observer* observer) = 0;// 接口方法,注銷觀察者virtual void detach(Observer* observer) = 0;// 接口方法,通知所有觀察者血量變化virtual void notifyHeath() = 0;// 接口方法,通知所有觀察者氣勢(shì)變化virtual void notifyMoraleChange() = 0;
};// **Monster類定義**
// 繼承自Subject,代表被觀察者(怪物)
class Monster : public Subject {
public:// 默認(rèn)構(gòu)造函數(shù),設(shè)置初始血量為100Monster() :_health(100) {}// 構(gòu)造函數(shù),允許設(shè)置初始血量Monster(int health) :_health(health) {}// 析構(gòu)函數(shù),刪除所有觀察者對(duì)象(假設(shè)Monster擁有觀察者對(duì)象所有權(quán))~Monster() {for(auto observer : _observers) {delete observer;}}// 實(shí)現(xiàn)attach方法,添加觀察者到列表void attach(Observer* observer) override {_observers.push_back(observer);}// 實(shí)現(xiàn)detach方法,從列表中移除指定觀察者void detach(Observer* observer) override {for(auto it = _observers.begin(); it != _observers.end(); ) {if(*it == observer) {it = _observers.erase(it);} else {++it;}}}// 實(shí)現(xiàn)notifyHeath,通知觀察者血量變化void notifyHeath() override {for(auto observer: _observers) {observer->updateHealthy(_health);}}// 實(shí)現(xiàn)notifyMoraleChange,通知觀察者氣勢(shì)變化void notifyMoraleChange() override {for(auto observer: _observers) {observer->updateMorel(_morale);}}// 減少怪物血量并增加氣勢(shì),同時(shí)通知觀察者void takeDamage(int damage) {_health -= damage;if (_health < 0) _health = 0;_morale += 20; // 氣勢(shì)增加notifyHeath(); // 通知血量變化notifyMoraleChange(); // 通知?dú)鈩?shì)變化}private:int _health; // 怪物的血量int _morale; // 怪物的氣勢(shì),默認(rèn)為0std::vector<Observer*> _observers; // 存儲(chǔ)觀察者指針的向量
};// **Classbuff類定義**
// 實(shí)現(xiàn)Observer接口,代表一個(gè)具體的觀察者(如血量條)
class Classbuff : public Observer {
public:// 實(shí)現(xiàn)更新血量顯示void updateHealthy(int health) override {std::cout << "Health Bar Update: Current HP is " << health << std::endl;}// 實(shí)現(xiàn)更新氣勢(shì)顯示void updateMorel(int morale) override {std::cout << "Morale Update: Current Morale is " << morale << std::endl;}
};
這段代碼通過觀察者模式展示了如何設(shè)計(jì)一個(gè)怪物類(Monster
)和一個(gè)觀察者類(Classbuff
)。怪物類負(fù)責(zé)維護(hù)血量和氣勢(shì)狀態(tài),并在狀態(tài)變化時(shí)通知所有注冊(cè)的觀察者。Classbuff
類作為觀察者,負(fù)責(zé)接收通知并打印出怪物的血量或氣勢(shì)變化信息。
我們來(lái)試試:
#define _CRT_SECURE_NO_WARNINGS 1
//#include "Monster.h"#include "monster_2.h"int main()
{Monster monster(100); // 創(chuàng)建一個(gè)初始血量為100的怪獸Classbuff* healthBar = new Classbuff(); // 使用指針以匹配detach操作// 怪獸注冊(cè)生命條觀察者monster.attach(healthBar);// 玩家攻擊,造成20點(diǎn)傷害monster.takeDamage(20);// 假設(shè)需要在某個(gè)時(shí)刻移除觀察者// monster.detach(healthBar);return 0;}
觀察者模式的優(yōu)缺點(diǎn)
觀察者模式(Observer Pattern)是一種行為設(shè)計(jì)模式,它定義了對(duì)象之間的一對(duì)多依賴關(guān)系,當(dāng)一個(gè)對(duì)象狀態(tài)改變時(shí),所有依賴于它的對(duì)象都會(huì)得到通知并自動(dòng)更新。以下是觀察者模式的主要優(yōu)點(diǎn)和缺點(diǎn):
優(yōu)點(diǎn)
- 松耦合性(Decoupling):觀察者模式通過抽象接口或抽象類定義了觀察者和被觀察者之間的交互,使得兩者之間的依賴關(guān)系變得松散。這提高了系統(tǒng)的可維護(hù)性和可擴(kuò)展性,因?yàn)樾薷囊粋€(gè)類不會(huì)直接影響到其他類。
- 靈活性和動(dòng)態(tài)性:可以很容易地在運(yùn)行時(shí)動(dòng)態(tài)添加新的觀察者對(duì)象或移除現(xiàn)有觀察者,而無(wú)需修改被觀察者的代碼,這使得系統(tǒng)非常靈活和易于擴(kuò)展。
- 廣播通知:被觀察者可以一次性通知所有注冊(cè)的觀察者,減少了代碼重復(fù),并且能夠確保狀態(tài)的同步更新。
- 模塊化:觀察者模式促進(jìn)了軟件模塊化設(shè)計(jì),觀察者和被觀察者可以獨(dú)立開發(fā)和測(cè)試,它們之間的交互通過接口標(biāo)準(zhǔn)化。
缺點(diǎn)
- 性能開銷:當(dāng)觀察者數(shù)量很大時(shí),通知所有觀察者可能會(huì)引起性能問題,尤其是在每次狀態(tài)變化都需要通知時(shí)。這可能涉及大量的遍歷和調(diào)用操作。
- 過度通知:如果被觀察者頻繁改變狀態(tài),可能會(huì)導(dǎo)致不必要的通知,觀察者可能接收到很多不必要的更新,增加了處理負(fù)擔(dān)。
- 循環(huán)依賴和復(fù)雜性:如果觀察者和被觀察者之間形成了復(fù)雜的相互依賴關(guān)系,可能會(huì)導(dǎo)致難以理解和維護(hù)的循環(huán)引用問題,甚至系統(tǒng)死鎖。
- 調(diào)試?yán)щy:由于觀察者模式的異步和松耦合特性,有時(shí)很難跟蹤和調(diào)試問題,尤其是當(dāng)多個(gè)觀察者同時(shí)響應(yīng)并可能互相影響時(shí)。
總的來(lái)說(shuō),觀察者模式適合那些需要維護(hù)多個(gè)對(duì)象間狀態(tài)同步,且這些對(duì)象之間的關(guān)系可以抽象為一對(duì)多依賴的場(chǎng)景。但在應(yīng)用時(shí)需要權(quán)衡其帶來(lái)的靈活性和可能的性能、維護(hù)問題。