前言:到目前已经看了几个设计模式,像简单工厂模式、策略模式、单一职责原则、开放-封闭原则、依赖倒转与装饰模式等。但总是纸上得来终觉浅的感觉,没有深 刻的理解。到现在感觉是可以进一步学习面向对象语言编程的特性,如何抽象基 类、虚函数的应用、如何通过基类进行对象间的解耦、由此需要复习C 虚函数、 多态等特性。
一、基本信息
1. 什么是观察者模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,会通知所有观察者,使观察者自己可以更新自己。
2. 观察者模式特点(☆☆☆☆☆)
①什么时候使用观察者模式
当一个对象改变需要同时改变其他对象的时候。
当不知道有多少具体对象需要改变时,使用观察者模式。
一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
②观察者模式作用
主要是在解耦。让耦合的双方都依赖于抽象,而不依赖于具体(抽象耦合)。从而使各自的变化不会影响到另一边的变化(依赖倒转原则)。并建立了一套触发机制。
个人理解,主要还是通过抽象基类进行解耦。
③缺点
如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
更新接口(update)只能统一调用,实际中并不一定统一。
二、程序实现
IDE使用Qt
1. 具体实现
抽象观察者,为具体观察者定义update接口,在得到主题通知时更新自己。
class Observer{public: Observer() {} virtual ~Observer() {} virtual void update() = 0;};
抽象主题为独立模块,仅与抽象观察者耦合,维护观察者列表,向众多观察者广播事件。
class Subject{public: Subject() {} virtual ~Subject() {}
public: //增加观察者 void attachObserver(Observer *observer) {m_observersList.push_back(observer);} //移除观察者 void detachObserver(Observer *observer) {m_observersList.remove(observer);} //通知 void notifyObsever(){ //C 11增加了range-for用法,简化了遍历写法 for(Observer *iter : m_observersList) { iter->update(); } }
private: //具体观察者列表 list<Observer *> m_observersList;};
具体主题,设置相关状态,并将状态传递给具体观察者。
class ConcreteSubject : public Subject{public: ConcreteSubject() {} virtual ~ ConcreteSubject() {}
public: void setSubjectState(const string state) {m_subjectState = state;} string getSubjectState() {return m_subjectState;}
private: string m_subjectState;};
具体观察者,实现抽象观察者的update接口,使自身状态与主题状态一致。具体观察者需要保存相关具体主题,也可以保存多个。类似于可以关注多个公众号。
class ConcreteObserver : public Observer{public: ConcreteObserver(ConcreteSubject *concreteSubject, string name): m_observerName(name),m_concreteSubject(concreteSubject) {} virtual ~ ConcreteObserver() {}
public: virtual void update(){ //观察者状态由发布者提供 m_observerState = m_concreteSubject->getSubjectState(); std::cout << "Observer " << m_observerName << " status is " << m_observerState << std::endl; }
private: string m_observerName; //观察者名称 string m_observerState; //所观察的具体主题,可观察多个 ConcreteSubject *m_concreteSubject;};
2. 具体调用
int main(int argc, char *argv[]){ ConcreteSubject *s = new ConcreteSubject(); ConcreteObserver *observerA = new ConcreteObserver(s, "A");
//添加3个观察者,更新状态并通知 s->attachObserver(observerA); s->attachObserver(new ConcreteObserver(s, "B")); s->attachObserver(new ConcreteObserver(s, "C"));
s->setSubjectState("start learn!"); s->notifyObsever();
//移除观察者A,更新状态并通知 s->detachObserver(observerA); s->setSubjectState("stop learn!"); s->notifyObsever();
QCoreApplication a(argc, argv);
return a.exec();}
文章参考大话设计模式与网上资料,侵删。
三、小结
直接看观察者模式的实现所获得的东西可能没有那么多,而且需要看很多遍,每次会有新的感悟。不妨看看大话设计模式的例子,从耦合的例子开始,看到最后面对这样一个需求是如何从耦合变得不那么耦合。有点数学定理公式,直接告诉你结果,但是却不知道来源与具体应用场景。