写点什么

13. 观察者模式设计思想

作者:杨充
  • 2024-11-13
    湖北
  • 本文字数:5866 字

    阅读完需:约 19 分钟

13.观察者模式设计思想

目录介绍

  • 01.观察者模式基础

  • 1.1 观察者模式由来

  • 1.2 观察者模式定义

  • 1.3 观察者模式场景

  • 1.4 观察者模式思考

  • 02.观察者模式实现

  • 2.1 罗列一个场景

  • 2.2 用例子理解观察者

  • 2.3 案例演变分析

  • 2.4 观察者模式基本实现

  • 03.观察者模式分析

  • 3.1 观察者模式案例

  • 3.2 观察者模式结构图

  • 3.3 观察者模式时序图

  • 04.观察者模式优缺点

  • 4.1 优点分析

  • 4.2 缺点分析

  • 4.3 符合设计原则分析

  • 05.观察者模式使用

  • 5.1 适用环境分析

  • 5.2 应用场景

  • 06.观察者模式总结

  • 6.1 总结一下学习

  • 6.2 更多内容推荐

推荐一个好玩网站

一个最纯粹的技术分享网站,打造精品技术编程专栏!编程进阶网


https://yccoding.com/

01.观察者模式基础

1.0 本博客 AI 摘要

本文详细介绍了观察者模式的设计思想,包括其定义、实现方式、优缺点及应用场景。通过微信公众号的例子,阐述了如何使用观察者模式实现对象间的依赖关系,确保一个对象状态改变时能自动通知其他对象。

1.1 观察者模式由来

建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。


在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系。可以根据需要增加和删除观察者,使得系统更易于扩展,这就是观察者模式的模式动机。


主要解决什么问题呢


一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。更多内容

1.2 观察者模式定义

观察者模式(Observer Pattern)的定义:


定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

1.3 观察者模式场景

观察者模式(Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern)更多内容


在 GoF 的《设计模式》一书中,它的定义是这样的:Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.


翻译成中文就是:在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。


一般情况下,被依赖的对象叫作被观察者(Observable),依赖的对象叫作观察者(Observer)。


在实际的项目开发中,这两种对象的称呼是比较灵活的,有各种不同的叫法,比如:Subject-Observer、Publisher-Subscriber、Producer-Consumer、EventEmitter-EventListener、Dispatcher-Listener。


只要应用场景符合刚刚给出的定义,都可以看作观察者模式。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

1.4 观察者模式思考

以下是一些关于观察者模式的思考:


  1. 可扩展性:观察者模式可以方便地扩展和添加新的观察者,而不需要修改被观察者的代码。

  2. 事件驱动:观察者模式常常与事件驱动编程结合使用。当被观察者的状态发生变化时,它会触发相应的事件,并通知所有的观察者进行相应的处理。

  3. 广播通知:观察者模式可以实现广播通知的功能,即一个被观察者可以同时通知多个观察者。这样可以方便地实现消息传递和事件处理。

02.观察者模式实现

2.1 罗列一个场景

需求:微信公众号。在使用微信公众号时,大家都会有这样的体验,当你关注的公众号中有新内容更新的话,它就会推送给关注公众号的微信用户端。


我们使用观察者模式来模拟这样的场景,微信用户就是观察者,微信公众号是观察对象,有多个的微信用户关注了程序猿这个公众号。更多内容


如何何时使用观察者模式?


一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。关键代码:在抽象类里有一个 ArrayList 存放观察者们。

2.2 用例子理解观察者

大概实现的思路是这样:


  1. 第一步:抽象观察者。定义一个接口,包含一个更新的抽象方法。

  2. 第二步:具体观察者。继承接口,实现抽象方法。

  3. 第三步:观察对象。定一个观察接口,包含添加订阅者,删除订阅者,通知订阅者抽象方法。

  4. 第四步:具体观察对象。具体主题角色类需要实现观察接口,然后用一个 list 集合存储观察者对象

  5. 第五步:测试,创建公众号对象,然后添加用户订阅公众号,公众号更新


第一步:抽象观察者


public interface Observer {    void update(String message);}
复制代码


第二步:具体观察者


//具体的观察者角色类public class WeiXinObserver implements Observer{    private String name;
public WeiXinObserver(String name) { this.name = name; }
@Override public void update(String message) { System.out.println(name + ": " + message); }}
复制代码


第三步:观察对象


//观察对象public interface Subject {
//添加订阅者(观察者对象) void attach(Observer observer);
//删除订阅者 void detach(Observer observer);
//通知订阅者更新消息 void notify(String message);}
复制代码


第四步:具体观察对象


//具体主题角色类public class SubscriptionSubject implements Subject{
//定义一个集合,用来存储多个观察者对象 private List<Observer> weiXinUserList = new ArrayList<>();
@Override public void attach(Observer observer) { weiXinUserList.add(observer); }
@Override public void detach(Observer observer) { weiXinUserList.remove(observer); }
@Override public void notify(String message) { //遍历集合 for (Observer observer : weiXinUserList) { //调用观察者对象中的 update 方法 observer.update(message); } }}
复制代码


第五步:测试,创建公众号对象,然后添加用户订阅公众号,公众号更新更多内容


private void test1() {    //1.创建公众号对象    SubscriptionSubject subject = new SubscriptionSubject();
//2.订阅公众号 subject.attach(new WeiXinObserver("打工充")); subject.attach(new WeiXinObserver("心怡宝")); subject.attach(new WeiXinObserver("逗比果"));
//3.公众号更新 subject.notify("打工充 设计模式专栏更新了!");}
复制代码


输出结果更新如下:


打工充: 打工充 设计模式专栏更新了!心怡宝: 打工充 设计模式专栏更新了!逗比果: 打工充 设计模式专栏更新了!
复制代码

2.3 案例演变分析

2.4 观察者模式基本实现

在观察者模式中有如下角色:


  • Subject:观察对象,定义了注册观察者和删除观察者的方法。此外,它还声明了“获取现在的状态”的方法。

  • SubscriptionSubject:具体观察对象,当自身状态发生变化后,它会通知所有已经注册的 Observer 角色。

  • Observer:抽象观察者,负责接收来自 Subject 角色的状态变化的通知,为此,它声明了 update 方法。

  • WeiXinObserver:具体观察者,当它的 update 方法被调用后,会去获取要观察的对象的最新状态。


根据上面微信公众号的案例,绘制 UML 图如下


03.观察者模式分析

3.1 观察者模式官方案例

定义主题接口(Subject):主题接口定义了注册、注销和通知观察者的方法。更多内容


public interface Subject {    void registerObserver(Observer observer);    void unregisterObserver(Observer observer);    void notifyObservers();}
复制代码


实现具体主题类(ConcreteSubject):具体主题类实现了主题接口,并维护一个观察者列表,用于注册、注销和通知观察者。


import java.util.ArrayList;import java.util.List;
public class ConcreteSubject implements Subject { private List<Observer> observers = new ArrayList<>();
@Override public void registerObserver(Observer observer) { observers.add(observer); }
@Override public void unregisterObserver(Observer observer) { observers.remove(observer); }
@Override public void notifyObservers() { for (Observer observer : observers) { observer.update(); } }}
复制代码


定义观察者接口(Observer):观察者接口定义了接收主题通知的方法。更多内容


public interface Observer {    void update();}
复制代码


实现具体观察者类(ConcreteObserver):具体观察者类实现了观察者接口,并在接收到主题通知时执行相应的操作。


public class ConcreteObserver implements Observer {    @Override    public void update() {        // 执行相应的操作    }}
//观察者1public class ConcreteObserverOne implements Observer { @Override public void update() { //TODO: 获取消息通知,执行自己的逻辑... System.out.println("ConcreteObserverOne is notified."); }} //观察者2public class ConcreteObserverTwo implements Observer { @Override public void update() { //TODO: 获取消息通知,执行自己的逻辑... System.out.println("ConcreteObserverTwo is notified."); }}
复制代码


实际上,上面的代码算是观察者模式的“模板代码”,只能反映大体的设计思路。


在真实的软件开发中,并不需要照搬上面的模板代码。观察者模式的实现方法各式各样,函数、类的命名等会根据业务场景的不同有很大的差别,万变不离其宗,设计思路都是差不多的。

3.2 观察者模式结构图

观察者模式包含如下角色:


  • Subject: 目标

  • ConcreteSubject: 具体目标

  • Observer: 观察者

  • ConcreteObserver: 具体观察者


观察者模式结构图如下所示


3.3 观察者模式时序图

观察者模式时序图如下所示:


04.观察者模式优缺点

4.1 优点分析

优点:


  • 1、观察者和被观察者解耦,增强了灵活性。

  • 2、符合开闭原则,容易扩展。

  • 3、支持广播通信,一个对象状态变化会通知多个观察者对象。

  • 4、建立一套触发机制。

4.2 缺点分析

缺点


  • 1、如果观察者很多,通知的开销很大。

  • 2、被观察者发送通知,无法知道有哪些观察者处理。更多内容


观察者模式的缺点也有一些


  • 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

  • 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

  • 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

4.3 符合设计原则分析

符合设计原则分析如下所示


  • 1、单一职责原则(Single Responsibility Principle) :观察者和被观察者职责明确区分,都仅负责自己的功能。

  • 2、开闭原则(Open Closed Principle) :可以新增观察者而不影响被观察者,扩展开放。

  • 3、里氏替换原则(Liskov Substitution Principle) :观察者都遵循统一接口,扩展观察者不会对系统造成影响。

  • 4、依赖倒转原则(Dependency Inversion Principle) :被观察者和观察者都依赖于抽象接口,不依赖具体实现。

  • 5、接口隔离原则(Interface Segregation Principle) :观察者接口只定义了更新接口,避免了冗余。更多内容

05.观察者模式使用

5.1 适用环境分析

在以下情况下可以使用观察者模式:


  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。

  • 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。

  • 一个对象必须通知其他对象,而并不知道这些对象是谁。

  • 需要在系统中创建一个触发链,A 对象的行为将影响 B 对象,B 对象的行为将影响 C 对象……,可以使用观察者模式创建一种链式触发机制。

5.2 应用场景

观察者模式在软件开发中应用非常广泛:凡是涉及到一对一或者一对多的对象交互场景都可以使用观察者模式。更多内容


  1. 如某电子商务网站可以在执行发送操作后给用户多个发送商品打折信息

  2. 某团队战斗游戏中某队友牺牲将给所有成员提示等等

  3. 比如邮件系统,很多人订阅了邮件信息,当有信息更新邮件系统会给所有订阅者发送消息

06.观察者模式总结

6.1 总结一下学习

01.观察者模式基础


  1. 主要解决什么问题呢?一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

  2. 模式动机:建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。

  3. 定义:定义对象间一对多依赖关系,当一个对象状态发生改变,其依赖对象都会收到通知并自动更新。


02.观察者模式实现


需求: 微信公众号。当你关注的公众号中有新内容更新的话,它就会推送给关注公众号的微信用户端。


大概实现的思路是这样:


  1. 第一步:抽象观察者。定义一个接口,包含一个更新的抽象方法。

  2. 第二步:具体观察者。继承接口,实现抽象方法。

  3. 第三步:观察对象。定一个观察接口,包含添加订阅者,删除订阅者,通知订阅者抽象方法。

  4. 第四步:具体观察对象。具体主题角色类需要实现观察接口,然后用一个 list 集合存储观察者对象

  5. 第五步:测试,创建公众号对象,然后添加用户订阅公众号,公众号更新


03.观察者模式分析


观察者模式包含如下角色:


  • Subject: 目标。

  • ConcreteSubject: 具体目标。

  • Observer: 观察者。主要是用来添加,移除观察者,当有消息时,会触发遍历通知具体观察者

  • ConcreteObserver: 具体观察者。比如,程序员 A,B,C,D,都关注了技术公众号


04.观察者模式优缺点


  1. 主要优点:在于可以实现表示层和数据逻辑层的分离,并在观察目标和观察者之间建立一个抽象的耦合,支持广播通信;

  2. 主要缺点:在于如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间,而且如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。


05.观察者模式使用


使用环境分析:一个对象改变导致其他多个对象也发生改变,可以降低对象之间耦合性。


应用场景:记住一句话,凡是涉及到一对多交互场景,则可以使用观察者模式。比如公众号订阅,邮件订阅,网站发送打折优惠券等。

6.2 更多内容推荐


23 种设计模式


6.3 更多内容


发布于: 刚刚阅读数: 4
用户头像

杨充

关注

还未添加个人签名 2018-07-30 加入

还未添加个人简介

评论

发布
暂无评论
13.观察者模式设计思想_杨充_InfoQ写作社区