2014年5月9日 星期五

【Design Pattern】Observer 觀察者模式

寫程式經常碰到改變一個值時,需要跟著改變的地方也很多,所以程式需要盡量降低耦合性。觀察者模式就定義了物件一對多的關係,發佈物件時可以自動通知所有訂閱者,降低直接依賴性。


  • 以下程式碼範例是指一家台灣彩卷發行1~99個號碼,所以買彩卷的人可以去跟彩卷行登記一個號碼,當彩卷行公布每一期的號碼時,會自動通知登記過的人是否有中獎。


#include < iostream >
#include < string >
#include < list >

using namespace std;


class LotteryObserver
{
public:
    virtual ~LotteryObserver() {};
    virtual void Update( int number, int buyer_number )= 0;
    virtual std::string getName() = 0;
    virtual int getNumber() = 0;
protected:
    LotteryObserver(){};
};

class Subject
{
public:
    virtual ~Subject() {};
    virtual void subscribeObsvr( LotteryObserver* obsvr ) = 0;
    virtual void unsubscribeObsvr( LotteryObserver* obsvr ) = 0;
    virtual void notifyObsvrs( int number ) = 0;
};

//台灣彩卷行可讓別人進行登記、取消登記及通知所有登記人中獎資訊
class TaiwanLottery : public Subject
{
public:
    TaiwanLottery(){
        _observers = new std::list< LotteryObserver* >();
    }
    void subscribeObsvr( LotteryObserver* obsvr );
    void unsubscribeObsvr( LotteryObserver* obsvr );
    void notifyObsvrs( int number);
private:
    std::list< LotteryObserver* > *_observers;
};

void TaiwanLottery::subscribeObsvr( LotteryObserver* obsvr )
{
    _observers->push_back( obsvr );
}

void TaiwanLottery::unsubscribeObsvr( LotteryObserver* obsvr )
{
    if (_observers->size() > 0)
        _observers->remove( obsvr );
}

void TaiwanLottery::notifyObsvrs( int number)
{
    std::cout << "Publish Number : " << number << std::endl;
    std::list< LotteryObserver* >::iterator iter = _observers->begin();

    for ( ;iter != _observers->end(); iter++ ) {
        int buyerNumber = (*iter)->getNumber();
        (*iter)->Update( number, buyerNumber );
    }
}


class LotteryBuyer : public LotteryObserver
{
public:
    LotteryBuyer( std::string name, int number ){
        _name   = name;
        _number = number;
    }
    void Update( int number, int buyer_number );
    std::string getName();
    int getNumber();
private:
    std::string _name;
    int _number;
};

std::string LotteryBuyer::getName()
{
    return _name;
}

int LotteryBuyer::getNumber()
{
    return _number;
}

void LotteryBuyer::Update(int number, int buyer_number)
{
    if ( number == buyer_number ){
        std::cout << "Congratulation: "<< _name <<" ,your number is " << buyer_number << std::endl;
    }
    else{
        std::cout << "Sorry : "<< _name <<" ,your number is " << buyer_number << std::endl;
    }
}


int main()
{
    LotteryBuyer* B = new LotteryBuyer( "Micheal", 15 );
    LotteryBuyer* C = new LotteryBuyer( "Alice", 22 );
    LotteryBuyer* D = new LotteryBuyer( "Marc", 77 );
    LotteryBuyer* E = new LotteryBuyer( "Sam", 21 );
    LotteryBuyer* F = new LotteryBuyer( "David", 19 );

    TaiwanLottery* store = new TaiwanLottery();
    store->subscribeObsvr(B);
    store->subscribeObsvr(C);
    store->subscribeObsvr(D);
    //公布第一次中獎的號碼是77
    store->notifyObsvrs(77);

    store->subscribeObsvr(E);
    store->subscribeObsvr(F);
    //公布第二次中獎的號碼是16
    store->notifyObsvrs(16);
    return 0;
}


參考來源:C++ API 設計

0 意見:

張貼留言