1. 程式人生 > >中介者模式與觀察者模式

中介者模式與觀察者模式

中介者模式

Mediator(中介者)模式是行為模式之一,在Mediator模式中,類之間的互動行為被統一放在Mediator的物件中,物件通過Mediator物件同其他物件互動,Mediator物件起著控制器的作用。
  用一箇中介物件來封裝一系列的物件互動,中介者使各物件不需要顯示的相互引用,從而降低耦合;而且可以獨立地改變它們之間的互動。
角色和職責
這裡寫圖片描述
這裡寫圖片描述
Mediator抽象中介者
中介者類的抽象父類。–定義了同事到中介的介面,包含了至少兩個抽象同事/關聯類相關的例項做成員變數,否則不能做中介!她得知道兩個(或以上)關聯類物件的資訊,才能做媒介!–抽象的婚介機構.
concreteMediator
具體的中介者類。–包含了具體的同事物件(成員變數)–好比世紀佳緣
Colleague
關聯類/同事類的抽象父類。–包含了中介者(成員變數、函式引數)–所有的人類。
concreteColleague
具體的關聯類/同事類。–只知道自己的屬性和行為,對其他物件不關心,都認識中介。–男人和女人/中國人和老外
適用於:
用一箇中介物件,封裝多個物件(同事)的交換,中介者使得各個物件不需要顯示的相互作用,從而實現瞭解耦合,而且可以獨立的改變他們之間的交換。
模式優點


1,將系統按功能分割成更小的物件,符合類的最小設計原則
2,對關聯物件的集中控制
3,減小類的耦合程度,明確類之間的相互關係:當類之間的關係過於複雜時,其中任何一個類的修改都會影響到其他類,不符合類的設計的開閉原則 ,而Mediator模式將原來相互依存的多對多的類之間的關係簡化為Mediator控制類與其他關聯類的一對多的關係,當其中一個類修改時,可以對其他關聯類不產生影響(即使有修改,也集中在Mediator控制類)。
4,有利於提高類的重用性
案例

/*******************************
 * 對要進行處理的關聯類進行抽象--抽象關聯類
 * --共同屬性和公共介面(純虛擬函式)
 * --包含了中介者做成員變數和函式引數
 * --公共接口裡面含有自身型別的指標或引用做函式引數
 *
 * 具體關聯類實現公共介面和建構函式
 *
 * 抽象中介者--包含多個關聯類的例項(獲取資訊)
 * --封裝多個關聯類的互動行為
 *
 * 案例中只使用了一個具體中介者,沒有進行派生
 *
*******************************/
#include <iostream> #include <string> using namespace std; /*中介者的前置宣告--抽象關聯類要用到中介者例項進行類的宣告--所以前置宣告*/ class Mediator; /*抽象關聯類*/ class Person { public: Person(string name,int condi,int sex,Mediator * mediator)//公共屬性的初始化--建構函式-- //裡面含有中介者做引數--將自己的資訊提供給中介者
{ m_name = name; m_condi = condi; m_sex = sex; m_mediator = mediator; } virtual void getParter(Person * p) = 0;//公共介面--實現互動--在這裡指匹配兩個關聯物件 /*返回關聯物件的相關屬性*/ string getName() { return m_name; } int getSex() { return m_sex; } int getCondi() { return m_condi; } protected: string m_name; int m_condi; int m_sex; Mediator * m_mediator;//中介者例項做成員變數 }; /*中介者--會在關聯類物件中被呼叫*/ class Mediator { public: void setWoman(Person *woman)//設定一個關聯類資訊 { m_pWoman = woman; } void setMan(Person *man)//設定另一個關聯類資訊 { m_pMan = man; } void getParter()//對多個關聯類進行互動 { if(m_pMan->getSex() == m_pWoman->getSex()) { cout <<"i am not gay"<<endl; return ; } if(m_pMan->getCondi() == m_pWoman->getCondi()) { cout<<m_pMan->getName()<<" and "<<m_pWoman->getName()<<" are OK "<<endl; }else{ cout<<m_pMan->getName()<<" and "<<m_pWoman->getName()<<" not OK!FUCK! "<<endl; } } private: /*將關聯類例項做成員變數--畢竟中介需要知道雙方資訊*/ Person *m_pMan; Person *m_pWoman; }; /*具體關聯類*/ class Man:public Person { public: /*呼叫父類建構函式--例項化子類物件*/ Man(string name,int condi,int sex,Mediator * mediator):Person(name,condi,sex,mediator) { } /*抽象關聯類的純虛擬函式的實現--關聯類的互動--最終呼叫中介者裡面的互動函式完成和另一個關聯物件的互動*/ virtual void getParter(Person * p) { m_mediator->setMan(this); m_mediator->setWoman(p); m_mediator->getParter(); } }; /*具體關聯類*/ class Woman:public Person { public: Woman(string name,int condi,int sex,Mediator * mediator):Person(name,condi,sex,mediator) { } virtual void getParter(Person * p) { m_mediator->setMan(p); m_mediator->setWoman(this); m_mediator->getParter(); } }; int main() { Mediator *mediator = new Mediator;//中介者例項化 Person * lzj = new Man("lzj",3,1,mediator);//男人例項化 Person * sqn = new Man("sqn",2,2,mediator);//女人例項化 Person * yrm = new Man("yrm",3,2,mediator); /*男人通過呼叫自己和其他物件的互動函式完成互動 *自己的互動函式會呼叫中介者的互動函式實現互動行為的打包封裝 * 實現關聯類之間的互動行為且解耦合 */ lzj->getParter(sqn); lzj->getParter(yrm); return 0; }

觀察者模式

Observer模式是行為模式之一,它的作用是當一個物件的狀態發生變化時,能夠自動通知其他關聯物件,自動重新整理物件狀態。
  Observer模式提供給關聯物件一種同步通訊的手段,使某個物件與依賴它的其他物件之間保持狀態同步。
角色及職責
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
Subject(被觀察者)
  被觀察的物件。當需要被觀察的狀態發生變化時,需要通知佇列中所有觀察者物件。Subject需要維持(新增,刪除,通知)一個觀察者物件的佇列列表。   
ConcreteSubject
被觀察者的具體實現。包含一些基本的屬性狀態及其他操作。
Observer(觀察者)
介面或抽象類。當Subject的狀態發生變化時,Observer物件將通過一個callback函式得到通知。
ConcreteObserver
觀察者的具體實現。得到通知後將完成一些具體的業務邏輯處理。
適用於:
定義物件間一種一對多的依賴關係,使得每一個物件改變狀態,則所有依賴於他們的物件都會得到通知。
案例
偵聽事件驅動程式設計中的外部事件
偵聽/監視某個物件的狀態變化
釋出者/訂閱者(publisher/subscriber)模型中,當一個外部事件(新的產品,訊息的出現等等)被觸發時,通知郵件列表中的訂閱者
使用場景:定義了一種一對多的關係,讓多個觀察物件(公司員工)同時監聽一個主題物件(祕書),主題物件狀態發生變化時,會通知所有的觀察者,使它們能夠更新自己。

#include <iostream>
#include <string>
#include <list>
using namespace std;

/*前置宣告--以便各個類宣告的時候使用對方*/
class PlayObserver;
class Secretary;


/*觀察者(本案例中沒有用抽象觀察者)
*--包含被觀察物件/主題物件做成員變數
*--如果使用抽象觀察者--具體觀察者會對主題物件的訊息產生不同動作的響應
*/
class PlayObserver
{
public:
    PlayObserver(Secretary *sec)//建構函式裡有主題物件做引數
    {
        m_sec = sec;
    }

    void Update(string action)//觀察者接收到被觀察者的狀態變化訊息以後的響應函式
    {
        cout<<action<<endl;
    }

private:
    Secretary *m_sec;//主題物件做成員變數
};


/*被觀察者--需要維持(新增,刪除,通知)一個觀察者物件的佇列列表。*/
class Secretary
{
public:

    Secretary()//建構函式
    {
        m_list.clear();
    }

    /*狀態發生變化的時候--會呼叫這個函式通知所有的觀察者*/
    void Notify(string info)
    {
        for(list<PlayObserver*>::iterator it = m_list.begin();it != m_list.end();it++)
        {
            (*it)->Update(info);
        }
    }

    /*設定觀察者--新增到觀察者佇列*/
    void setPlayObserver(PlayObserver* o)
    {
        m_list.push_back(o);
    }


private:
    list<PlayObserver*> m_list;//觀察者佇列
};



int main()
{

    Secretary * tmp_sec = NULL;//被觀察者

    /*定義兩個觀察者物件*/
    PlayObserver * po1 = NULL;
    PlayObserver * po2 = NULL;

    /*例項化被觀察者*/
    tmp_sec = new Secretary;

    /*例項化觀察者*/
    po1 = new  PlayObserver(tmp_sec);
    po2 = new  PlayObserver(tmp_sec);

    /*被觀察者設定觀察者物件*/
    tmp_sec->setPlayObserver(po1);
    tmp_sec->setPlayObserver(po2);

    /*被觀察者狀態改變--通知所有觀察者*/
    tmp_sec->Notify("boss coming");


    /*記憶體回收*/
    delete tmp_sec;
    delete   po1;
    delete   po2;

    return 0;
}