自学教程 学编程从这里开始

观察者模式

《观察者模式》|设计模式系列第23篇

系列:行为型模式 · 观察者模式(Observer Pattern)
关键词:发布订阅、一对多联动、主题、观察者、事件通知、松耦合

一、什么是观察者模式

观察者模式(Observer Pattern):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

属于行为型设计模式。

简单理解:
主题(Subject)内部维护一组观察者列表。当主题状态发生变化,自动广播消息通知所有已注册观察者;观察者收到通知后执行自己的更新逻辑。观察者只订阅主题,主题只知道观察者统一接口,双方松耦合。
例子:新闻订阅,报社(主题)发布新闻,所有订阅读者(观察者)收到推送;前端事件监听、消息通知。

核心意图
建立一对多依赖;主题状态变更,自动通知所有订阅观察者。

适用场景

  1. 一个对象状态变化,其他多个对象需要同步响应
  2. 事件监听、消息推送、数据变更通知
  3. 广播通知场景,订阅者动态增减
  4. MVC 模型,Model变更通知View更新

⚠️ 缺点预警:通知是顺序同步执行,观察者过多会阻塞;循环依赖会触发死循环;无法知道通知是否成功处理。

二、UML结构图

角色划分:

  1. Subject(抽象主题):提供注册、移除观察者、通知接口
  2. ConcreteSubject(具体主题):保存状态,状态变更时触发通知
  3. Observer(抽象观察者):定义update通知回调接口
  4. ConcreteObserver(具体观察者):实现update方法,收到通知执行业务
  5. Client(客户端):创建主题与观察者,完成订阅

三、Java 完整示例

场景:WeatherStation 气象站(主题),推送温度信息;Display 显示屏观察者。代码全部使用英文。

import java.util.ArrayList;
import java.util.List;

// Observer
public interface Observer {
    void update(float temperature);
}

// Subject
public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// ConcreteSubject
public class WeatherStation implements Subject {
    private List<Observer> observerList = new ArrayList<>();
    private float temperature;

    public void setTemperature(float temperature) {
        this.temperature = temperature;
        notifyObservers();
    }

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

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

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

// ConcreteObserver
public class CurrentDisplay implements Observer {
    @Override
    public void update(float temperature) {
        System.out.println("CurrentDisplay: temperature = " + temperature);
    }
}

public class StatDisplay implements Observer {
    @Override
    public void update(float temperature) {
        System.out.println("StatDisplay: temperature = " + temperature);
    }
}

// Client
public class Client {
    public static void main(String[] args) {
        Subject weatherStation = new WeatherStation();
        Observer currentDisplay = new CurrentDisplay();
        Observer statDisplay = new StatDisplay();

        weatherStation.registerObserver(currentDisplay);
        weatherStation.registerObserver(statDisplay);

        ((WeatherStation) weatherStation).setTemperature(25.6f);
        weatherStation.removeObserver(statDisplay);
        ((WeatherStation) weatherStation).setTemperature(28.1f);
    }
}

运行输出:

CurrentDisplay: temperature = 25.6
StatDisplay: temperature = 25.6
CurrentDisplay: temperature = 28.1

四、观察者模式 vs 中介者模式

模式目标核心
Observer一对多单向广播,主题推送消息给订阅者主题发布,观察者被动接收,观察者之间互不感知
Mediator多对多双向交互,全部由中介转发多个同事通过中介通信,同事之间无直接引用

五、优缺点总结

✅ 优点

  1. 主题与观察者松耦合,只依赖抽象接口
  2. 动态新增/删除观察者,运行时订阅取消订阅
  3. 符合开闭原则,新增观察者不修改主题代码

❌ 缺点

  1. 默认同步通知,观察者耗时会阻塞主线程
  2. 没有消息持久化,未订阅的观察者收不到历史消息
  3. 存在循环调用风险

六、框架源码应用

  • JDK java.util.Observer(已废弃)、java.util.EventListener
  • Spring ApplicationEvent 事件监听
  • Guava EventBus
  • RxJava 响应式流(思想同源)

七、小结

观察者模式核心:主题维护观察者列表;状态变更,自动调用所有观察者update方法推送消息。
开发中优先使用框架事件机制(Spring Event / Guava EventBus),很少手写原生观察者;适合事件广播、数据变更通知场景。

标签:

0 条笔记