拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

23种设计模式‑观察者(Observer)设计模式

23种设计模式‑观察者(Observer)设计模式
文章目录
  • 一.什么是观察者模式?
  • 二.观察者模式的结构
  • 三.观察者模式的应用场景
  • 四.观察者模式的优缺点
  • 五.观察者模式的实现(C++示例)
  • 六.观察者模式的实现(JAVA示例)
  • 七.代码解释
  • 八.总结

类图:观察者设计模式类图

一.什么是观察者模式?

观察者模式(Observer Pattern)是一种行为型设计模式,用于定义对象之间的一对多依赖关系。即一个对象(称为“主题”Subject,也叫被观察者)状态发生改变时,会自动通知依赖它的其他对象(称为“观察者”Observer),观察者收到通知后自动更新自身行为。

这种模式在很多场景中都非常适用,比如发布-订阅系统、事件监听、界面刷新等。

观察者模式的核心特点是松耦合:观察者和主题不需要彼此了解内部实现细节,只需按照约定的接口进行交互,这种设计大幅提升了代码的可维护性和可扩展性。

二.观察者模式的结构

  1. Subject(主题 / 被观察者):又称被观察者,用于存储和管理观察者列表,定义注册、移除观察者的接口,并在自身状态变化时遍历通知所有观察者。
  2. Observer(观察者):观察者抽象接口,用于定义统一的更新方法,所有具体观察者都必须实现该接口。
  3. ConcreteSubject(具体主题):继承/实现主题接口,实现具体的状态管理,以及状态变化时通知观察者的具体逻辑。
  4. ConcreteObserver(具体观察者):实现观察者接口,接收主题的更新通知,根据主题的新状态执行相应的业务行为。

三.观察者模式的应用场景

  1. 发布-订阅系统:消息推送、内容订阅,主题发布新内容时,所有订阅者自动接收通知。
  2. GUI事件监听:桌面/前端界面的按钮点击、键盘输入等事件,组件状态变化触发监听者响应。
  3. 数据联动刷新:MVC架构中模型层数据变化后,多视图面板自动同步刷新。
  4. 配置中心同步:分布式系统中配置中心更新后,所有服务节点自动同步最新配置。
  5. 监控告警系统:监控指标异常时,自动推送给多个告警渠道(邮件、短信、即时通讯)。

四.观察者模式的优缺点

优点

  1. 主题与观察者深度解耦:双方仅依赖抽象接口,互不依赖具体实现,新增任意一方都无需修改对方代码,符合开闭原则。
  2. 天然支持一对多广播:主题状态变化时自动通知所有已注册观察者,无需客户端手动逐个调用。
  3. 动态灵活:运行时可以随时注册、移除观察者,不影响主题和其他观察者的运行。
  4. 抽象层建立依赖:在抽象层面定义对象联动关系,适配不同的具体实现类。

缺点

  1. 通知效率随观察者数量下降:观察者数量较多时,遍历通知的耗时会线性增加。
  2. 存在循环依赖风险:若观察者同时也是主题,互相观察可能触发循环通知,导致系统异常。
  3. 默认通知粒度粗:原生通知仅告知“状态已变化”,若需要传递具体变更内容,需要额外设计参数协议。
  4. 内存泄漏风险:长生命周期的主题中,观察者若未正确注销,会一直被持有引用,无法释放。

五.观察者模式的实现(C++示例)

示例场景:技术公众号(具体主题)发布文章,所有关注的订阅用户(具体观察者)自动收到推送;用户可随时关注/取消关注。

#include<iostream>#include<vector>#include<string>#include<algorithm>usingnamespacestd;// Observer:抽象观察者接口classObserver{public:virtual~Observer()=default;// 统一更新接口,接收主题推送的状态virtualvoidupdate(conststring&message)=0;};// Subject:抽象主题(被观察者)接口classSubject{public:virtual~Subject()=default;virtualvoidattach(Observer*observer)=0;// 注册观察者virtualvoiddetach(Observer*observer)=0;// 移除观察者virtualvoidnotify()=0;// 通知所有观察者};// ConcreteSubject:具体主题 - 公众号classOfficialAccount:publicSubject{private:vector<Observer*>observers;// 观察者列表string latestArticle;// 主题内部状态:最新文章public:// 发布新文章:状态变化,触发通知voidpublishArticle(conststring&title){latestArticle=title;cout<<"\n公众号发布新文章:《"<<title<<"》"<<endl;notify();}voidattach(Observer*observer)override{observers.push_back(observer);}voiddetach(Observer*observer)override{autoit=find(observers.begin(),observers.end(),observer);if(it!=observers.end()){observers.erase(it);}}voidnotify()override{for(Observer*obs:observers){obs->update(latestArticle);}}};// ConcreteObserver:具体观察者 - 订阅用户classUser:publicObserver{private:string userName;public:User(string name):userName(name){}voidupdate(conststring&message)override{cout<<"用户【"<<userName<<"】收到推送:"<<message<<endl;}};// 客户端测试代码intmain(){// 创建主题OfficialAccount*techBlog=newOfficialAccount();// 创建观察者Observer*user1=newUser("张三");Observer*user2=newUser("李四");Observer*user3=newUser("王五");// 注册观察者(用户关注公众号)techBlog->attach(user1);techBlog->attach(user2);techBlog->attach(user3);// 状态变化,广播通知techBlog->publishArticle("详解观察者设计模式");// 移除观察者(李四取消关注)techBlog->detach(user2);cout<<"\n李四取消关注公众号"<<endl;// 再次状态变化,仅通知剩余观察者techBlog->publishArticle("C++设计模式实战");// 释放内存deleteuser1;deleteuser2;deleteuser3;deletetechBlog;return0;}

C++运行输出

公众号发布新文章:《详解观察者设计模式》 用户【张三】收到推送:详解观察者设计模式 用户【李四】收到推送:详解观察者设计模式 用户【王五】收到推送:详解观察者设计模式 李四取消关注公众号 公众号发布新文章:《C++设计模式实战》 用户【张三】收到推送:C++设计模式实战 用户【王五】收到推送:C++设计模式实战

六.观察者模式的实现(JAVA示例)

importjava.util.ArrayList;importjava.util.List;// 抽象观察者interfaceObserver{voidupdate(Stringmessage);}// 抽象主题interfaceSubject{voidattach(Observerobserver);voiddetach(Observerobserver);voidnotifyObservers();}// 具体主题:公众号classOfficialAccountimplementsSubject{privateList<Observer>observers=newArrayList<>();privateStringlatestArticle;publicvoidpublishArticle(Stringtitle){this.latestArticle=title;System.out.println("\n公众号发布新文章:《"+title+"》");notifyObservers();}@Overridepublicvoidattach(Observerobserver){observers.add(observer);}@Overridepublicvoiddetach(Observerobserver){observers.remove(observer);}@OverridepublicvoidnotifyObservers(){for(Observerobs:observers){obs.update(latestArticle);}}}// 具体观察者:用户classUserimplementsObserver{privateStringuserName;publicUser(Stringname){this.userName=name;}@Overridepublicvoidupdate(Stringmessage){System.out.println("用户【"+userName+"】收到推送:"+message);}}// 客户端publicclassObserverDemo{publicstaticvoidmain(String[]args){OfficialAccounttechBlog=newOfficialAccount();Observeruser1=newUser("张三");Observeruser2=newUser("李四");Observeruser3=newUser("王五");techBlog.attach(user1);techBlog.attach(user2);techBlog.attach(user3);techBlog.publishArticle("详解观察者设计模式");techBlog.detach(user2);System.out.println("\n李四取消关注公众号");techBlog.publishArticle("Java设计模式实战");}}

七.代码解释

  1. Observer 抽象观察者
    定义统一的update()接口,屏蔽不同观察者的业务差异;主题只面向接口通知,不需要知道具体观察者的类型和内部逻辑。
  2. Subject 抽象主题
    约定三个核心能力:注册、移除、通知观察者;是观察者模式解耦的核心,主题仅依赖抽象观察者集合。
  3. ConcreteSubject 具体主题
    内部维护观察者列表,持有自身业务状态;当状态发生变化时,调用notify()遍历所有观察者,调用其update()方法完成广播。
  4. ConcreteObserver 具体观察者
    实现update()方法,接收主题推送的状态,执行自身的业务逻辑;每个观察者独立处理通知,互不影响。
  5. 松耦合体现
    新增观察者类无需修改主题代码,新增主题类也无需修改现有观察者,两者完全通过抽象接口交互。

八.总结

观察者模式核心:定义一对多的对象依赖,主题状态变化时自动通知所有观察者,实现触发式联动,同时保持主题与观察者的松耦合。

关键点

  1. 归属:行为型设计模式,别名:发布-订阅模式、源-监听器模式。
  2. 四大角色:抽象主题Subject、具体主题ConcreteSubject、抽象观察者Observer、具体观察者ConcreteObserver。
  3. 核心优势:解耦、一对多广播、动态增删观察者、符合开闭原则。
  4. 适用场景:事件驱动、消息推送、多视图同步、分布式配置同步等需要联动的场景。
  5. 易混淆区分:观察者是状态变化主动通知;迭代器是客户端主动遍历访问。
返回列表