观察者模式:

  指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

观察者模式的角色:

  1. 抽象目标(Subject):也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
  2. 具体目标(ConcreteSubject):也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
  3. 抽象观察者(Observer):它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
  4. 具体观察者(ConcreteObserver):实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

观察者模式的应用场景:

  1. 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
  2. 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时,可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。

优点:

观察者和被观察者是抽象耦合的;建立的一套触发机制。

缺点:

  1. 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
  2. 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
  3. 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

eg:

class Observer {
public:
	Observer();
	virtual ~Observer();
	virtual void Update()=0;
};

//---------------------------------------------
class ConcreteObserver :public Observer{
public:
	ConcreteObserver(ConcreteSubject *sub,string name){
		pSubject = sub;
		mName = name;
	}
	void Update(){
		mObserverState = pSubject->mSubjectState;
		cout << "观察者" << mName << " 状态" <<mObserverState<<endl;
	}
	virtual ~ConcreteObserver();
 
	ConcreteSubject* getSubject()  {
		return pSubject;
	}
 
	void setSubject( ConcreteSubject* subject) {
		pSubject = subject;
	}
 
private:
	string mName;
	string mObserverState;
	ConcreteSubject *pSubject;
};
//---------------------------------------------
class Subject {
public:
	Subject();
	virtual ~Subject();
	void Attach(Observer* p){
		observers.push_back(p);
	}
	void Remove(Observer* p){
		observers.remove(p);
	}
	void Notify(){
		list <Observer* >::iterator it;
		for(it = observers.begin();it!=observers.end();it++){
			(*it)->Update();
		}
	}
	list <Observer* > observers ;
};

class ConcreteSubject :public Subject{
public:
	ConcreteSubject();
	virtual ~ConcreteSubject();
 
	string getSubjectState() {
		return mSubjectState;
	}
 
	void setSubjectState(const string& subjectState) {
		mSubjectState = subjectState;
	}
 
	string mSubjectState;
 
};

//---------------------------------------------
//use
	ConcreteSubject * p = new ConcreteSubject();
	p->Attach(new ConcreteObserver(p,"X"));
	p->Attach(new ConcreteObserver(p,"Y"));
	p->mSubjectState ="ABC";
	p->Notify();