观察者模式
理论
观察者模式,定义了一对多得依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。观察者模式又叫做发布-订阅(Publish/Subscribe)模式。
观察者模式的特点:
将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。而观察者模式的关键对象是主题 Subject 和观察者 Observer,一个 Subject 可以有任意数目的依赖它的Observer,一旦 Subject 的状态发生了改变,所有的 Observer 都可以得到通知。Subject 发出通知时并不需要知道谁是它的观察者,而任何一个具体观察者也不需要知道其他观察者的存在。
观察者模式的应用场景:
1. 当一个对象的改变需要同时改变其他对象的时候,而且它不知道具有多少对象有待改变时。
2. 当一个抽象模型有两个方面,其中一方面依赖另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。
观察者模式所做地工作其实就是在解除耦合。让耦合的双方都依赖抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。
实例
公司同事上班摸鱼,想让前台帮忙在老板回来的时候打电话通知他们
初步实现:双向耦合
//前台(通知者)发现老板回来,通知同事(观察者)不要摸鱼(状态) #include <iostream> #include <list> using namespace std; class Observer; //前向引用说明 //通知者类 class Subject { public: //增加观察者 void Attach(Observer* observer) { observers.push_back(observer); } //移除观察者 void Detach(Observer* observer) { observers.remove(observer); } //通知 void Notify(); //状态 string SubjectState(string subjectState) { this->subjectState = subjectState; return subjectState; } private: list<Observer*> observers; //观察者列表 string subjectState; }; //观察者类 class Observer { public: Observer(string name, Subject* _subject) { this->Name = name; this->subject = _subject; } //采取行动 void Update(string subjectState) { this->observerState = subject->SubjectState(subjectState); cout << "观察者:" << this->Name << " 状态:" << this->observerState << " 停止摸鱼" << endl; } private: string Name; string observerState; Subject* subject; }; void Subject::Notify() { for (list<Observer*>::iterator it = observers.begin(); it != observers.end(); it++) { (*it)->Update(subjectState); } } //客户端 int main() { //创建一个通知者 Subject* secretory = new Subject(); //增加观察者 secretory->Attach(new Observer("小张", secretory)); secretory->Attach(new Observer("小王", secretory)); //发现老板,改变状态 secretory->SubjectState("老板回来了!"); //通知观察者改变状态 secretory->Notify(); system("pause"); return 0; }
解耦实现一
#include <iostream> #include <list> using namespace std; class Subject; //抽象观察者类 class AbstractObserver { public: virtual void Update(string subjectState) = 0; }; //通知者类 class Subject { public: //针对抽象编程,减少了与具体类之间的耦合 void Attach(AbstractObserver* observer) { observers.push_back(observer); } void Detach(AbstractObserver* observer) { observers.remove(observer); } void Notify() { for (list<AbstractObserver*>::iterator it = observers.begin(); it != observers.end(); it++) { (*it)->Update(subjectState); } } string SubjectState(string subjectState) { this->subjectState = subjectState; return subjectState; } private: list<AbstractObserver*> observers; string subjectState; }; //具体观察者类 class Observer1 : public AbstractObserver { public: Observer1(string name, Subject* _subject) { Name = name; subject = _subject; } void Update(string subjectState) { this->observerState = subject->SubjectState(subjectState); cout << "观察者:" << this->Name << " 状态:" << this->observerState << " 停止打游戏" << endl; } private: string Name; string observerState; Subject* subject; }; class Observer2 : public AbstractObserver { public: Observer2(string name, Subject* _subject) { Name = name; subject = _subject; } void Update(string subjectState) { this->observerState = subject->SubjectState(subjectState); cout << "观察者:" << this->Name << " 状态:" << this->observerState << " 停止刷视频" << endl; } private: string Name; string observerState; Subject* subject; }; //客户端 int main() { Subject* secretory = new Subject(); secretory->Attach(new Observer1("小张", secretory)); secretory->Attach(new Observer2("小王", secretory)); secretory->SubjectState("老板回来了!"); secretory->Notify(); system("pause"); return 0; }
解耦实现二:观察者模式
UML类图
代码实现
#include <iostream> #include <list> using namespace std; //抽象观察者类 class AbstractObserver { public: virtual void Update(string subjectState) = 0; }; //抽象通知者类 class AbstractSubject { public: virtual void Attach(AbstractObserver* observer) = 0; virtual void Detach(AbstractObserver* observer) = 0; virtual void Notify() = 0; string SubjectState(string subjectState) { this->subjectState = subjectState; return subjectState; } protected: string subjectState; }; //具体通知者类 class Subject1 : public AbstractSubject { public: //针对抽象编程,减少了与具体类之间的耦合 void Attach(AbstractObserver* observer) { observers.push_back(observer); } void Detach(AbstractObserver* observer) { observers.remove(observer); } void Notify() { for (list<AbstractObserver*>::iterator it = observers.begin(); it != observers.end(); it++) { (*it)->Update(subjectState); } } string SubjectState(string subjectState) { this->subjectState = subjectState; return subjectState; } private: list<AbstractObserver*> observers; }; //具体观察者类 class Observer1 : public AbstractObserver { public: Observer1(string name, AbstractSubject* _subject){ Name = name; subject = _subject; } void Update(string subjectState) { this->observerState = subject->SubjectState(subjectState); cout << "观察者:" << this->Name << " 状态:" << this->observerState << " 停止打游戏" << endl; } protected: string Name; string observerState; AbstractSubject* subject; }; class Observer2 : public AbstractObserver { public: Observer2(string name, AbstractSubject* _subject) { Name = name; subject = _subject; } void Update(string subjectState) { this->observerState = subject->SubjectState(subjectState); cout << "观察者:" << this->Name << " 状态:" << this->observerState << " 停止刷视频" << endl; } protected: string Name; string observerState; AbstractSubject* subject; }; //客户端 int main() { AbstractSubject* secretory1 = new Subject1(); secretory1->Attach(new Observer1("小张", secretory1)); secretory1->Attach(new Observer2("小王", secretory1)); secretory1->SubjectState("老板回来了!"); secretory1->Notify(); system("pause"); return 0; }
观察者模式的不足:
尽管已经用了依赖倒转原则,但是“抽象通知者”还是依赖“抽象观察者”,也就是说,万一没有了抽象观察者这样的接口,通知的功能就完不成。另外就是每个具体观察者,它不一定是“更新”的方法要调用。
所以如果通知者和观察者之间相互不知道,可以由客户端来决定通知谁。
后续:可用委托机制来进行改进。