行为型设计模式——观察者模式
文章目录观察者模式结构实现特点观察者模式在软件系统中对象并不是孤立存在的一个对象行为的改变可能会导致一个或多个其他与之存在依赖关系行为发生改变它们之间将会产生联动“触一发而动百发”。为了更好的描述对象之间存在的这种一对多的联动产生了观察者模式Observer Pattern这一解决方案。场景使用的社交软件当关注的博主更新了内容会收到提示信息购买的商品被送到菜鸟驿站会收到驿站发送的提示信息订阅了报刊每天/每月都会收到新的报纸或者杂志观察者模式是一种软件设计模式其中一个称为主体的对象维护其依赖项列表称为观察者并通常通过调用其方法之一自动将任何状态更改通知它们。定义对象之间的一种一对多的依赖关系使得每当一个对象状态发生改变时其相关依赖对象都得到通知并被自动更新。在观察者模式中发生改变的对象称为观察目标而被通知的对象称为观察者一个观察目标可以对应多个观察者而且这些观察者之间可以没有任何相互联系可以根据需要增加和删除观察者使得系统更易于扩展。观察者模式的别名包括发布-订阅Publish/Subscribe模式、模型-视图Model/View模式、源-监听器Source/Listener模式、从属者Dependents模式。结构在观察者模式结构图中包含如下几个角色Subject目标目标又称为主题它是指被观察的对象。在目标中定义了一个观察者集合一个观察目标可以接受任意数量的观察者来观察它提供一系列方法来增加和删除观察者对象同时它定义了通知方法notify()。目标类可以是接口也可以是抽象类或具体类。ConcreteSubject具体目标具体目标是目标类的子类通常它包含有经常发生改变的数据当它的状态发生改变时向它的各个观察者发出通知同时它还实现了在目标类中定义的抽象业务逻辑方法。如果无须扩展目标类则具体目标类可以省略。Observer观察者观察者将对观察目标的改变做出反应观察者一般定义为接口该接口声明了更新数据的方法update()因此又称为抽象观察者。Concrete Observer具体观察者在具体观察者中维护一个指向具体目标对象的引用它存储具体观察者的有关状态这些状态需要和具体目标的状态保持一致它实现了在抽象观察者Observer中定义的update()方法。通常在实现时可以调用具体目标类的attach()方法将自己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除。实现// 声明订阅者类, 只是做了声明, 并没有包含这个类的头文件classObserver;// 新闻社classNewsAgency{public://添加一个订阅者到list 容器中voidattach(Observer*ob){m_list.push_back(ob);}//从list 容器中删除一个订阅者voiddeatch(Observer*ob){m_list.remove(ob);}//将通知信息发送给list 容器中的所有订阅者virtualvoidnotify(string msg)0;virtual~NewsAgency(){};protected:// 订阅者列表,将所有的订阅者对象存储到STL的list 容器中listObserver*m_list;};// 摩根斯的新闻社classMorgans:publicNewsAgency{public:voidnotify(string msg)override;};voidMorgans::notify(string msg){cout摩根斯新闻社报纸的订阅者一共有m_list.size()人endl;for(constautoitem:m_list){item-update(msg);// 订阅者类的定义在下面}}// 八卦新闻classGossip:publicNewsAgency{public:voidnotify(string msg)override;};voidGossip::notify(string msg){cout八卦新闻社报纸的订阅者一共有m_list.size()人endl;for(constautoitem:m_list){item-update(msg);}}#pragmaonce#includestring#includeiostream#includeNewsAgency.husingnamespacestd;// 抽象的订阅者类classObserver{public://通过发布者对象将观察者对象存储了起来这样就可以收到发布者推送的消息了。Observer(string name,NewsAgency*news):m_name(name),m_news(news){m_news-attach(this);}//观察者取消订阅取消之后将不再接收订阅消息。voidunsubscribe(){m_news-deatch(this);}//观察者得到最新消息之后用于更新自己当前的状态。virtualvoidupdate(string msg)0;virtual~Observer(){}protected:string m_name;NewsAgency*m_news;};classDragon:publicObserver{public:usingObserver::Observer;voidupdate(string msg)override{cout路飞的老爸革命军龙收到消息: msgendl;}};classShanks:publicObserver{public:usingObserver::Observer;voidupdate(string msg)override{cout路飞的引路人红发香克斯收到消息: msgendl;}};classBartolomeo:publicObserver{public:usingObserver::Observer;voidupdate(string msg)override{cout路飞的头号粉丝巴托洛米奥收到消息: msgendl;}};intmain(){Morgans*msnewMorgans;Gossip*gossipnewGossip;Dragon*dragonnewDragon(蒙奇·D·龙,ms);Shanks*shanksnewShanks(香克斯,ms);Bartolomeo*bartonewBartolomeo(巴托洛米奥,gossip);ms-notify(蒙奇·D·路飞成为新世界的新的四皇之一, 赏金30亿贝里!!!);coutendl;gossip-notify(女帝汉库克想要嫁给路飞, 给路飞生猴子, 哈哈哈...);deletems;deletegossip;deletedragon;deleteshanks;deletebarto;return0;}特点⚠️观察者模式是一种使用频率非常高的设计模式无论是移动应用、Web应用或者桌面应用观察者模式几乎无处不在它为实现对象之间的联动提供了一套完整的解决方案凡是涉及到一对一或者一对多的对象交互场景都可以使用观察者模式。主要优点观察者模式可以实现表示层和数据逻辑层的分离定义了稳定的消息更新传递机制并抽象了更新接口使得可以有各种各样不同的表示层充当具体观察者角色。观察者模式支持广播通信观察目标会向所有已注册的观察者对象发送通知简化了一对多系统设计的难度。观察者模式满足“开闭原则”的要求增加新的具体观察者无须修改原有系统代码在具体观察者与观察目标之间不存在关联关系的情况下增加新的观察目标也很方便。主要缺点如果一个观察目标对象有很多直接和间接观察者通知所有的观察者会花费很多时间。如果在观察者和观察目标之间存在循环依赖观察目标会触发它们之间进行循环调用可能导致系统崩溃。观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的而仅仅只是知道观察目标发生了变化。适用环境当一个对象状态的改变需要改变其他对象时可使用观察者模式。需要在系统中创建一个触发链A对象的行为将影响B对象B对象的行为将影响C对象……可以使用观察者模式创建一种链式触发机制。