觀察者模式 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);
}
};
實驗結果: