当前位置: 首页 > article >正文

设计模式学习之——观察者模式

观察者模式是一种行为型设计模式,它用于在对象之间建立一对多的依赖关系。

一、定义与角色

  • 定义
    • 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
  • 主要角色
    • 主题(Subject):也称为被观察者,它维护一个观察者列表,并提供注册、删除和通知观察者的方法。
    • 观察者(Observer):对主题的状态变化感兴趣,并在状态变化时做出响应。它定义了一个更新方法,用于接收和处理主题的通知。
    • 具体主题(ConcreteSubject):实现了主题接口,维护了观察者的集合,并在状态变化时通知所有观察者。
    • 具体观察者(ConcreteObserver):实现了观察者接口,并对主题的状态变化做出具体的反应。

二、工作原理

  1. 注册观察者:观察者通过调用主题的注册方法,将自己添加到主题的观察者列表中。
  2. 状态变化通知:当主题的状态发生变化时,它会遍历观察者列表,并调用每个观察者对象的更新方法,将新的状态传递给观察者。
  3. 观察者响应:观察者对象接收到主题的通知后,执行相应的操作,以便响应状态的变化。

三、优缺点

优点: 

  1. 解耦性:主题和观察者之间是松耦合的,它们之间通过抽象的接口进行通信,使得它们可以独立地进行修改和扩展。
  2. 可扩展性:可以方便地增加新的观察者,而无需修改主题的代码。
  3. 灵活性:观察者模式支持同步和异步通知,观察者可以在不同的线程中执行更新操作。
  4. 规范性:观察者模式定义了主题和观察者之间的一套规范,使得代码更具可读性和可维护性。

缺点/注意事项:

  1. 循环依赖:避免在观察者和主题之间建立循环依赖关系,否则可能导致系统崩溃。
  2. 性能问题:当观察者数量非常多时,通知操作可能会非常耗时。可以考虑使用异步通知、事件总线等优化方法。
  3. 内存泄漏:如果观察者对象不再需要,确保从主题的观察者列表中删除它们,以避免内存泄漏。
  4. 线程安全:在多线程环境中,确保对观察者列表的访问是线程安全的。可以使用同步机制、并发集合等来实现。

四、应用场景

  1. 数据变化通知:当对象的状态发生变化,需要通知多个对象进行更新时,可以使用观察者模式。例如,股票市场的系统中,投资者需要实时获取股票价格的变化。
  2. 分布式事件系统:需要将事件从一个组件广播到多个组件时,可以使用观察者模式。例如,GUI框架中的事件处理机制,用户的操作需要通知多个界面组件。
  3. 系统状态监控:当系统的状态变化需要被监控时,可以使用观察者模式。例如,应用程序的日志系统、系统监控工具等。

五、示例代码

以下是一个简单的观察者模式示例代码,用于演示其工作原理:

// 主题接口
public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 具体主题类
public class ConcreteSubject implements Subject {
    private List<Observer> observers = new LinkedList<>();
    private int state;

    public void setState(int state) {
        this.state = state;
        notifyObservers();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        observers.forEach(observer -> observer.update(state));
    }
}

// 观察者接口
public interface Observer {
    void update(int state);
}

// 具体观察者类
public class ConcreteObserver implements Observer {
    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(int state) {
        System.out.println(name + "接收到了更新请求,新的状态:" + state);
    }
}

// 测试类
public class ObserverPatternExample {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        Observer observer1 = new ConcreteObserver("观察者1号");
        Observer observer2 = new ConcreteObserver("观察者2号");

        subject.registerObserver(observer1);
        subject.registerObserver(observer2);

        subject.setState(10); // 输出:观察者1号接收到了更新请求,新的状态:10;观察者2号接收到了更新请求,新的状态:10
    }
}

六、与发布-订阅模式的比较

观察者模式和发布-订阅模式都是软件设计模式,用于实现对象间的一对多依赖关系,但它们之间存在一些关键的区别。以下是对这两种模式的详细比较:

定义与特点
  • 观察者模式

    • 定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。
    • 主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
    • 观察者和主题之间是抽象耦合的,即它们之间通过接口或抽象类进行交互,而不是直接依赖具体实现。
  • 发布-订阅模式

    • 也称为发布/订阅模式或消息传递模式。
    • 在这种模式下,消息的发送者(发布者)和接收者(订阅者)不需要建立直接的联系,也不需要知道对方的存在。
    • 消息的传递通过一个被称为代理(Broker)或调度中心的中间角色来完成。发布者将消息发布到代理上,而订阅者则从代理订阅感兴趣的消息。
结构与角色
  • 观察者模式

    • Subject(主题/被观察者):维护一个观察者列表,提供注册、删除和通知观察者的方法。
    • Observer(观察者):定义了一个更新接口,用于接收来自主题的通知。
    • ConcreteSubject(具体主题):实现Subject接口,维护观察者列表,并在状态变化时调用所有观察者的更新方法。
    • ConcreteObserver(具体观察者):实现Observer接口,定义当接收到主题通知时的具体行为。
  • 发布-订阅模式

    • 发布者(Publisher):负责将消息发布到主题上。发布者一次只能向一个主题发送数据,且发布消息时无需关心订阅者是否在线。
    • 订阅者(Subscriber):通过订阅主题接收消息。订阅者可一次订阅多个主题,从而接收感兴趣的消息。
    • 代理(Broker):负责所有消息的路由和分发工作。代理接收到发布者的消息后,根据主题将其分发给相应的订阅者。
    • 主题(Topic):用于标识消息的类别。每个消息都包含一个主题,订阅者通过订阅主题来接收感兴趣的消息。
区别与联系
  • 区别

    • 耦合性:观察者模式中,发布者与订阅者直接关联,发布者维护观察者列表,发布者状态变更通知订阅者。而在发布-订阅模式中,订阅者与发布者相互不了解,通过事件中心(代理)进行通信,实现了完全松耦合。
    • 角色数量:观察者模式中只有两个主要角色:观察者和被观察者。而发布-订阅模式中则包含四个角色:发布者、订阅者、代理和主题。
    • 应用场景:观察者模式多用于单个应用内部,而发布-订阅模式则更多的是一种跨应用的模式(cross-application pattern),如消息中间件等。
  • 联系

    • 两者都实现了对象间的一对多依赖关系,当某个对象的状态发生变化时,都会通知所有依赖的对象。
    • 两者都关注对象之间的通讯,并致力于保持对象间的低耦合和高协作性。

综上所述,观察者模式和发布-订阅模式在定义、结构、耦合性、角色数量和应用场景等方面都存在明显的区别。选择哪种模式取决于具体的应用需求和设计考虑。

最后,观察者模式是一种强大的设计模式,它能够在对象之间建立一对多的依赖关系,并自动通知观察者进行更新。然而,在实际应用中需要注意其潜在的性能问题和循环依赖问题


http://www.kler.cn/a/415623.html

相关文章:

  • 关于node全栈项目打包发布linux项目问题总集
  • 清远榉之乡托养机构探讨:自闭症的本质辨析
  • helm部署golang服务
  • 多线程+线程池
  • docker服务容器化
  • 【C语言】结构体、联合体、枚举类型的字节大小详解
  • 在openEuler中使用top命令
  • 【C++】list模拟实现(完结)
  • 电子电气架构 --- 面向服务的汽车诊断架构
  • 【docker】细致且具有时效性的docker在ubuntu的安装,新鲜出炉
  • python图像彩色数字化
  • PVE相关名词通俗表述方式———多处细节实验(方便理解)
  • 实践五 网络安全防范技术
  • Android复习代码1-4章
  • Codigger Desktop:多样 Look 设计,全新 Game Look 带来趣味体验
  • 数据结构——哈夫曼编码
  • 鸿蒙学习相关术语
  • 如何画出漂亮的决策树?
  • 【maven-4】IDEA 配置本地 Maven 及如何使用 Maven 创建 Java 工程
  • 自动类型推导(auto 和 decltype);右值引用和移动语义
  • mysql8.0基础-锁基础(七)
  • neo4j desktop版命令行中导入导出dump
  • Unity之一键创建自定义Package包
  • 题目 3209: 蓝桥杯2024年第十五届省赛真题-好数
  • 信息学奥赛一本通 1448:【例题1】电路维修 | 洛谷 P4667 [BalticOI 2011 Day1] Switch the Lamp On 电路维修
  • 《使用Python进行数据挖掘:理论、应用与案例研究》