Java设计模式:行为型模式→观察者模式

Java 观察者模式详解

1. 定义

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了一种一对多的依赖关系,使得当一个对象的状态发生变化时,所有的依赖者(观察者)都会得到通知并自动更新。观察者模式常用于事件处理系统和发布-订阅系统,能够实现对象之间的松耦合。

2. 基本思想

观察者模式的基本思想是将目标对象(被观察者)和依赖对象(观察者)解耦,使得它们之间可以独立变化。当被观察者的状态变化时,它会主动通知所有越来越多的观察者,这样观察者能根据需要更新自己的状态。通过这种模式,为系统的扩展和维护提供了灵活性。

3. 基本原理

观察者模式主要由以下几个组成部分构成:

  • 被观察者接口(Subject):提供注册、注销和通知观察者的方法。
  • 具体被观察者(Concrete Subject):实现被观察者接口,维护观察者列表,并在状态改变时通知观察者。
  • 观察者接口(Observer):定义观察者应实现的更新方法。
  • 具体观察者(Concrete Observer) :实现观察者接口,定义当被观察者状态变化时的响应行为。

更多实用资源:

http://sj.ysok.net/jydoraemon 访问码:JYAM

4. 实现方式

4.1 基本实现

4.1.1 被观察者接口

首先定义一个被观察者接口:

java 复制代码
import java.util.ArrayList;
import java.util.List;

public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}
4.1.2 具体被观察者

实现一个具体被观察者,维护状态并通知观察者:

java 复制代码
public class WeatherStation implements Subject {
    private List<Observer> observers;
    private float temperature;

    public WeatherStation() {
        observers = new ArrayList<>();
    }

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

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

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature);
        }
    }

    public void setTemperature(float temperature) {
        this.temperature = temperature;
        notifyObservers(); // 状态变化时通知观察者
    }
}
4.1.3 观察者接口

定义观察者接口,处理通知的方法:

java 复制代码
public interface Observer {
    void update(float temperature);
}
4.1.4 具体观察者

实现具体观察者,注册到被观察者中并响应通知:

java 复制代码
public class CurrentConditionsDisplay implements Observer {
    private float temperature;

    @Override
    public void update(float temperature) {
        this.temperature = temperature;
        display();
    }

    public void display() {
        System.out.println("Current temperature: " + temperature + "F");
    }
}
4.1.5 客户端代码

客户端代码,创建被观察者和观察者的关系:

java 复制代码
public class Client {
    public static void main(String[] args) {
        WeatherStation weatherStation = new WeatherStation();
        CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();

        weatherStation.registerObserver(currentDisplay);
        
        // 模拟天气变化
        weatherStation.setTemperature(80);
        weatherStation.setTemperature(82);
        weatherStation.setTemperature(78);
    }
}

4.2 代码分析

  • 被观察者接口(Subject):提供了观察者注册与注销,以及通知的方法定义。
  • 具体被观察者(WeatherStation):实现了被观察者接口,维护观察者列表并在状态变化时通知它们。
  • 观察者接口(Observer):定义了观察者需要实现的更新方法。
  • 具体观察者(CurrentConditionsDisplay):实现了观察者接口,能够响应状态变化并进行展示。
  • 客户端:通过实现的接口、类建立观察者和被观察者之间的关系,动态响应变化。

5. 工作流程

  1. 定义被观察者接口:创建接口定义注册、移除和通知观察者的方法。
  2. 实现具体被观察者:定义维护状态和观察者列表的具体被观察者,并在状态变更时调用通知方法。
  3. 定义观察者接口:创建接口定义观察者的响应方法。
  4. 实现具体观察者:实现观察者接口的具体类,处理状态变化的逻辑。
  5. 客户端使用:通过被观察者注册观察者,触发状态的变化,从而执行观察者的响应。

6. 变种

  1. 推模型和拉模型:在观察者模式中,推模型是由被观察者主导分发数据,而拉模型由观察者请求数据。
  2. 多级观察者:实现多个层次的观察者,利用链式关系形成多级结构。

7. 实际应用

观察者模式在实际应用场景中非常广泛,以下是一些常见的应用示例:

  1. 事件处理系统:GUI 库中的事件监听可以视为观察者模式的实现,界面元素作为被观察者,事件监听器作为观察者。
  2. 消息订阅系统:在聊天程序或新闻广播中,用户可订阅或取消订阅消息推送,从而接收感兴趣的内容。
  3. 股票价格监测:股票价格变化时,所有的观察者(如投资者)将收到更新通知。

8. 使用场景

使用观察者模式的场景包括:

  • 当一个对象状态变化需要同时改变其他对象,且不希望这些对象之间有紧密耦合时。
  • 当客户端需要订阅某些事件并处理相应逻辑时。
  • 当需要推送更新消息的场景,能够处理多个人员接收并响应。

9. 优缺点

优点

  1. 低耦合:观察者与被观察者之间没有紧密耦合关系,提高了系统的灵活性。
  2. 动态添加和撤销观察者:可以在运行时自由增加和注销观察者,增强系统的可扩展性。
  3. 符合开闭原则:在不修改已有代码的情况下,可增加新的观察者。

缺点

  1. 性能问题:如果观察者数量庞大,通知运行可能影响系统性能。
  2. 难以控制顺序:通知观察者的顺序可能难以控制,特别是在多层次观察者结构中。
  3. 潜在内存泄漏:在移除观察者时需要特别小心,若未正确移除可能造成内存泄漏。

10. 最佳实践

  1. 确认压力测试:在使用观察者模式时,保证在大数据量下的性能能得到保证。
  2. 确保观察者实现一致性:观察者的实现应保持一致并简明,减少内部复杂性。
  3. 适当使用弱引用:可以采取弱引用来防止观察者和被观察者之间造成内存泄漏。

11. 注意事项

  1. 注意顺序和优先级问题:在多人同时观察同一对象时,考虑通知的顺序和优先级。
  2. 提高状态的一致性:尽量控制观察者更新的时机,以增强观察者状态的一致性。
  3. 考虑分发量:评估外部条件变化时观察者的更新频率和数量。

12. 常见的误区

  • 认为所有事件都应使用观察者模式:观察者模式适合事件驱动或需要对应状态变化的场景,不同场景应选用合适设计模式。
  • 认为观察者一定是单一的:实际上,观察者可以以多种方式实现,可以设置不同的注册接口以支持多样化。
  • 假设无状态观察者状态是好的:无状态可能引入额外复杂性,确保具备合适的状态管理至关重要。

13. 常见问题

  • 观察者模式的核心组成部分是什么?

    • 包括被观察者接口、具体被观察者、观察者接口和具体观察者。
  • 如何判断使用观察者模式的适用性?

    • 当多个对象需要同时响应另一个对象的状态变化,并且不希望二者强制耦合时,适合使用观察者模式。
  • 观察者模式和其他模式(如发布-订阅模式)的区别是什么?

    • 观察者模式一般是对象之间的线性关系,而发布-订阅模式通常是在一个中心化的发布者与多个订阅者之间的松耦合关系,消息通过一个中介者传递。

14. 总结

观察者模式作为一种行为型设计模式,能够有效通过松耦合的方式管理对象间的关系,确保在对象状态发生变化时能自动通知相关的观察者。这种模式使得系统能够灵活扩展和维护,提高了对象之间的协作能力。在实际的开发中,了解观察者模式的基本原理和最佳实践,将有助于开发者设计出更为高效和灵活的程序架构。通过合理使用观察者模式,可以提高应用程序的可扩展性和可维护性,非常适合在事件驱动和多互动环境中实施。掌握好观察者模式对于提升代码质量和增强系统灵活性具有重要意义。

相关推荐
master-dragon1 小时前
Java锁自定义实现到aqs的理解
java·开发语言
hamster20211 小时前
力扣【1049. 最后一块石头的重量 II】Java题解(背包问题)
java·算法·leetcode
Cikiss2 小时前
「全网最细 + 实战源码案例」设计模式——桥接模式
java·后端·设计模式·桥接模式
Dr_Si3 小时前
CF 761A.Dasha and Stairs(Java实现)
java·开发语言
你爱写程序吗(新H)3 小时前
基于微信小程序的停车场管理系统设计 停车场微信小程序的设计与实现 (源码+文档)
java·spring boot·微信小程序·小程序
讓丄帝愛伱3 小时前
Java 泛型<? extends Object>
java·开发语言·python
Dr_Si3 小时前
CF 764B.Timofey and cubes(Java实现)
java·算法·排序算法
大秦王多鱼4 小时前
Kafka常见问题之 java.io.IOException: Disk error when trying to write to log
java·运维·分布式·kafka
千禧年@5 小时前
Spring的AOP面向切面编程思想
java·后端·spring