觀察者模式 Observer Pattern

觀察者模式 Observer Pattern

1.定義

觀察者模式定義了對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。

2.要點

  • 將一個系統分割成一個一些類相互協作的類有一個不好的副作用,那就是需要維護相關對象間的一致性。我們不希望爲了維持一致性而使各類緊密耦合,這樣會給維護、擴展和重用都帶來不便。觀察者就是解決這類的耦合關係的。
  • 目前廣泛使用的MVC模式,究其根本,是基於觀察者模式的。

3.使用場景:

  • 當一個抽象模式有兩個方面,其中一個方面依賴於另一個方面,需要將這兩個方面分別封裝到獨立的對象中,彼此獨立地改變和複用的時候。
  • 當一個系統中一個對象的改變需要同時改變其他對象內容,但是又不知道待改變的對象到底有多少個的時候。
  • 當一個對象的改變必須通知其他對象作出相應的變化,但是不能確定通知的對象是誰的時候。

4.模式解析

圖示:
這裏寫圖片描述

5.代碼實例:

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

//抽象觀察者(Observer)角色
class Observer
{
public:
    virtual void Update() = 0;
};

//抽象主題(Subject)角色
class Subject
{
public:
    void Attach( Observer* observer)
    {
        _observers.push_back(observer);
    }

    void Detach(Observer* observer)
    {
        std::list<Observer*>::iterator it = _observers.begin();
        for( ; it != _observers.end() ; it++ )
        {
            if(  *it == observer )
            {
                _observers.erase(it);
                break;
            }
        }
    }

    void Notify()
    {
        for(Observer *ob : _observers )
        {
            ob->Update();
        }
    }
private:
    std::list<Observer*> _observers;
};


class ConcreteSubject : public Subject
{
public:
    void set( string state)
    {
        _subjectState = state ;
    }
    string get()
    {
        return _subjectState;
    }

private:
    string _subjectState;
};


// 具體觀察者(ConcreteObserver)角色
class ConcreteObserver : public Observer
{
public:
    ConcreteObserver( ConcreteSubject* subject , string name  )
    {
        _subject = subject ;
        _name    = name;
    }
    virtual void Update()
    {
        _observerState = _subject->get();
        cout<<"Observer "<<_name<<"'s new state is "<<_observerState<<endl;
    }

    void SetSubject( ConcreteSubject* subject )
    {
        _subject = subject;
    }

    ConcreteSubject* GetSubject()
    {
        return _subject;
    }

private:
    string _name;
    string _observerState;
    ConcreteSubject* _subject;
};


class ObserverExample1
{
public:
    ObserverExample1(void);
    ~ObserverExample1(void);

    void Start()
    {
        ConcreteSubject* s = new ConcreteSubject();
        s->Attach( new ConcreteObserver( s , "X") );
        s->Attach( new ConcreteObserver( s , "Y") );
        s->Attach( new ConcreteObserver( s , "Z") );

        s->set("ABC");
        s->Notify();

        s->set("666");
        s->Notify();
    }
};

實驗結果:
這裏寫圖片描述

6.應用實例(股票):

/**
    Stock類保存所有購買了該股票的投資者,
    當股票價格發生變動時,同時所有的投資者
**/
#pragma once
#include <iostream>
#include <list>
#include <string>
using namespace std;

class Stock ;

//投資者
class IInvestor
{
public:
    virtual void Update(Stock * stock) = 0;
};

class Stock //股票
{
public:
    Stock(string symbol, double price)
    {
        _symbol = symbol;
        _price  = price;
    }

    void Attach(IInvestor* investor)
    {
        _investors.push_back(investor);
    }

    void Detach(IInvestor* investor)
    {
        list<IInvestor*>::iterator it = _investors.begin();
        for( ; it != _investors.end() ; it++ )
        {
            if( *it == investor )
            {
                _investors.erase(it);
                break;
            }
        }
    }

    void Notify()
    {
        for( IInvestor * v : _investors)
        {
            v->Update(this);
        }
        cout<<"Stock Notify( ) called"<<endl;
    }

    double getPrice()
    {
        return _price;
    }
    void setPrice( double price)
    {
        if( _price != price)
        {
            _price = price;
            Notify();
        }
    }

    string getSymbol()
    {
        return _symbol;
    }

private:
    string _symbol; // 標識
    double _price;
    list<IInvestor*> _investors;
};

class IBM : public Stock
{
public:
    IBM( string symbol, double price )
        : Stock(symbol,price)
    {
    }
};

class Investor : public IInvestor
{
public:
    Investor(string name)
    {
        _name = name;
    }

    void Update(Stock * stock)
    {
        cout<<"Notified " <<_name<<" of "<<stock->getSymbol()<<"'s change to "<<stock->getPrice()<<endl;
    }

    Stock* getStock()
    {
        return _stock;
    }
    void setStock( Stock*  stock )
    {
        _stock = stock ;
    }
private:
    string  _name;
    Stock*  _stock;
};

class ObserverExample2
{
public:
    ObserverExample2(void);
    ~ObserverExample2(void);

    void Start()
    {
        IBM *ibm = new IBM("IBM",120.00);
        ibm->Attach(new Investor("Jack" ));

        ibm->setPrice(120.10);
        ibm->setPrice(122.00);
        ibm->setPrice(120.05);
        ibm->setPrice(119.10);
        ibm->setPrice(119.70);

    }
};

實驗結果:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章