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; }; #endif
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; } }
代码中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; }; #endif
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); } }
代码中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; }