標籤:
1意圖
定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。
2別名
依賴(Dependents), 發布-訂閱(Publish-Subscribe)
3動機
將一個系統分割成一系列相互協作的類有一個常見的副作用:需要維護相關對象間的一致性。我們不希望為了維持一致性而使各類緊密耦合,因為這樣降低了他們的可重用性。
4實用性
1、當一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將二者封裝在獨立的對象中以使他們可以各自獨立的改變和複用。
2、當對一個對象的改變需要同時改變其它對象,而不知道具體有多少對象待改變。
3、當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之,你不希望這些對象是緊密耦合的。
5結構
7優缺點
1、使目標和觀察者之間的耦合是抽象的最小的。
2、支援廣播通訊
3、意外的更新 因為一個觀察者並不知道其它觀察者的存在,它可能對改變目標的最終代價一無所知。在目標上一個看視無害的操作可能會引起一系列對觀察者以及依賴這些觀察者的那些對象的更新。此外,如果依賴準則的定義或維護不當,常常會引起錯誤的更新,這種錯誤通常很難補捉。
--以上內容來自《可複用面向對向軟體的基礎》
代碼執行個體:
本例子簡單的類比車輛運行和紅綠燈的關係。例子中實現了一個Signallamp的基類(observer),凡是繼承這個基類的類都可以觀察紅綠燈資訊,並讓(concreteObserver)類Vehicle,繼承Signallamp。實現了一個subject的基類,凡是繼承subject的concretesubject都可以被繼承Signallamp的具體觀察者觀察,並實現子類TrafficSignal。
在用戶端我們實現了幾輛車在運行,當紅綠燈變化時,有觀察紅綠燈的車將收影響。所以:
這裡圖片沒有說明什麼,但可以方便我們想象到用戶端情境。許多車在不斷的移動,當變成紅燈的時候,那些觀察TrafficSignal事件的車輛將停止移動,而沒有觀察該事件的車將不受影響。
1、observer.h中代碼如下:
#ifndef _OBSERVER_#define _OBSERVER_#include <iostream>using namespace std;void gotoxy(int x,int y);enum Signallamp{RedSignal, GreenSignal};class ObserverTrafficSignal{public: ObserverTrafficSignal(){} virtual void updataSignal(Signallamp signal) = 0;};class Vehicle: public ObserverTrafficSignal{public: Vehicle(int px, int py):_pointx(px), _pointy(py){isRed = false;} void drawVehicle(); void clearVehicle(); void updataposition(); void setmovestep(int stepx, int stepy); virtual void updataSignal(Signallamp signal);private: int _pointx; int _pointy; int _move_x; int _move_y; int _save_movex; int _save_movey; bool isRed;};#endifobserver.h
2、observer.cpp中的代碼如下:
#include "observer.h"#include <iostream>using namespace std;#include<windows.h>void gotoxy(int x,int y){ COORD coord={x,y}; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);}void conceal_cursor(){ CONSOLE_CURSOR_INFO cci; cci.bVisible = false; cci.dwSize = sizeof(cci); HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorInfo(handle, &cci);}void Vehicle::drawVehicle(){ //conceal_cursor(); int i=0; gotoxy(_pointx, _pointy+(i++)); cout<<" __________________"; gotoxy(_pointx, _pointy+(i++)); cout<<"| |"; gotoxy(_pointx, _pointy+(i++)); cout<<"|[_][_][_][_][_][_]|"; gotoxy(_pointx, _pointy+(i++)); cout<<"|o _ _ _ |"; gotoxy(_pointx, _pointy+(i++)); cout<<" `(_)-------(_)(_)-\"";}void Vehicle::clearVehicle(){ int i=0; gotoxy(_pointx, _pointy+(i++)); cout<<" "; gotoxy(_pointx, _pointy+(i++)); cout<<" "; gotoxy(_pointx, _pointy+(i++)); cout<<" "; gotoxy(_pointx, _pointy+(i++)); cout<<" "; gotoxy(_pointx, _pointy+(i++)); cout<<" ";}void Vehicle::updataposition(){ _pointx += _move_x; _pointy += _move_y; if(_pointx > 80 ) _pointx = 1; if(_pointy>50) _pointy = 1; if(_pointy<1) _pointy = 50; if(_pointx<1) _pointx = 80;}void Vehicle::setmovestep(int stepx, int stepy){ _move_x = stepx; _move_y = stepy; }void Vehicle::updataSignal(Signallamp signal){ switch(signal) { case RedSignal: if(!isRed) { isRed = true; _save_movex = _move_x; _save_movey = _move_y; setmovestep(0, 0); } break; case GreenSignal: if(isRed) { setmovestep(_save_movex, _save_movey); isRed = false; } break; }}observer.cpp
代碼中updataSignal函數在遇見紅燈時,用_save_movex和_save_movey儲存了車子原始的移動速度,以便變成綠燈時恢複。
3、subject.h中的代碼如下:
#ifndef _SUBJECT_#define _SUBJECT_#include <list>using std::list;#include "observer.h"class subject{public: subject(){} virtual void attach(ObserverTrafficSignal* ob); virtual void detach(ObserverTrafficSignal* ob); virtual void notify() = 0; list<ObserverTrafficSignal* > _observers;};class TrafficSignal:public subject{public: TrafficSignal():_countTime(8),_signal(GreenSignal){} virtual void notify();private: int _countTime; Signallamp _signal;};#endifsubject.h
4、subject.cpp中的代碼如下:
#include "subject.h"#include<iostream>#include <iterator>using std::iterator;void subject::attach(ObserverTrafficSignal* ob){ if(NULL != ob) _observers.push_back(ob);}void subject::detach(ObserverTrafficSignal* ob){ if(NULL != ob) _observers.remove(ob);}void TrafficSignal::notify(){ if(!_countTime) { _countTime = rand()%5 + 4; ; if(_signal == RedSignal) _signal = GreenSignal; else _signal = RedSignal; } _countTime--; gotoxy(30, 4); if(_signal == RedSignal) std::cout<<"--紅燈--"; else std::cout<<"--綠色--"; list<ObserverTrafficSignal* >::iterator iter = _observers.begin(); for(iter; iter != _observers.end(); iter++) { (*iter)->updataSignal(_signal); }}subject.cpp
代碼中notify函數通過隨即一個數_countTime的簡單的類比了紅綠燈(只有紅燈和綠燈),每一次運行將_countTime減一,當_countTime等於零時再次隨即一個數,並更好紅綠燈。
5、main.cpp中的代碼如下:
#include <iostream>using namespace std;#include <time.h>#include "subject.h"int main(){ srand(time(0)); Vehicle ve1(80, 5); ve1.setmovestep(-3, 0); Vehicle ve2(80, 12); ve2.setmovestep(-4, 0); Vehicle ve3(80, 20); ve3.setmovestep(-2, 0); TrafficSignal tra; tra.attach(&ve1); //tra.attach(&ve2); tra.attach(&ve3); while(1) { ve1.drawVehicle(); ve2.drawVehicle(); ve3.drawVehicle(); _sleep(200); ve1.clearVehicle(); ve2.clearVehicle(); ve3.clearVehicle(); ve1.updataposition(); ve2.updataposition(); ve3.updataposition(); tra.notify(); } return 0;}
觀察者模式(observer)c++實現