20.设计模式-OBSERVER(观察者)

一、模式定义与核心思想

观察者模式是一种行为型设计模式,其核心目标是建立对象间一对多的依赖关系,使得当目标对象(Subject)状态变化时,所有依赖它的观察者(Observer)都能自动接收通知并更新自身状态。

核心价值

  1. 解耦对象关系:将观察者与被观察者解耦,避免直接依赖(如GUI界面与数据模型的分离)。
  2. 动态扩展性:支持运行时动态添加/移除观察者(如电商系统中新增促销通知渠道)。
  3. 状态同步机制:确保多个对象状态的一致性(如Excel表格与图表联动更新)。

典型应用场景

  • 用户界面组件的事件响应(如按钮点击触发多个控件更新)
  • 分布式系统的消息发布/订阅(如Kafka消息队列)
  • 游戏引擎的角色状态同步(如玩家位置变化触发怪物AI响应)

二、模式组成与UML类图

核心角色
  1. Subject(抽象目标)
    • 维护观察者集合,提供注册(attach())、注销(detach())和通知(notify())的接口。
  1. ConcreteSubject(具体目标)
    • 存储具体业务状态(如温度传感器数据),状态变化时触发通知。
  1. Observer(抽象观察者)
    • 定义更新接口update(),用于接收目标状态变更通知。
  1. ConcreteObserver(具体观察者)
    • 实现业务响应逻辑(如更新UI界面、发送短信通知)。
UML类图
classDiagram
    class Subject {
        <<interface>>
        +attach(Observer)
        +detach(Observer)
        +notify()
    }

    class ConcreteSubject {
        -state: int
        +getState()
        +setState(int)
    }

    class Observer {
        <<interface>>
        +update()
    }

    class ConcreteObserverA {
        -subject: Subject
        +update()
    }

    class ConcreteObserverB {
        -subject: Subject
        +update()
    }

    Subject <|-- ConcreteSubject
    Observer <|-- ConcreteObserverA
    Observer <|-- ConcreteObserverB
    ConcreteSubject --> Observer : notifies
    ConcreteObserverA --> ConcreteSubject : observes


三、代码实现示例

场景:实现气象站数据变化通知多个显示设备

1. 抽象目标与观察者
// 抽象目标
interface WeatherSubject {
    void registerObserver(WeatherObserver o);
    void removeObserver(WeatherObserver o);
    void notifyObservers();
}

// 抽象观察者
interface WeatherObserver {
    void update(float temp, float humidity);
}
2. 具体目标实现
class WeatherStation implements WeatherSubject {
    private List<WeatherObserver> observers = new ArrayList<>();
    private float temperature;
    private float humidity;

    @Override
    public void registerObserver(WeatherObserver o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(WeatherObserver o) {
        observers.remove(o);
    }

    @Override
    public void notifyObservers() {
        for (WeatherObserver o : observers) {
            o.update(temperature, humidity);
        }
    }

    public void setMeasurements(float temp, float humidity) {
        this.temperature = temp;
        this.humidity = humidity;
        notifyObservers();
    }
}
3. 具体观察者实现
class PhoneDisplay implements WeatherObserver {
    @Override
    public void update(float temp, float humidity) {
        System.out.printf("手机端更新: 温度%.1f℃ 湿度%.1f%%\n", temp, humidity);
    }
}

class WebDashboard implements WeatherObserver {
    @Override
    public void update(float temp, float humidity) {
        System.out.printf("网页端更新: 温度%.1f℃ 湿度%.1f%%\n", temp, humidity);
    }
}
4. 客户端调用
public class Client {
    public static void main(String[] args) {
        WeatherStation station = new WeatherStation();
        WeatherObserver phone = new PhoneDisplay();
        WeatherObserver web = new WebDashboard();

        station.registerObserver(phone);
        station.registerObserver(web);

        station.setMeasurements(25.5f, 65); // 触发双端通知
        station.removeObserver(web);
        station.setMeasurements(26.0f, 60); // 仅手机端更新
    }
}

四、工业级源码应用

  1. Java内置支持
    • java.util.Observable类与Observer接口(已废弃,但广泛用于早期Swing组件)
    • PropertyChangeListener在JavaBean中的状态监听实现
  1. Spring框架
    • ApplicationEventApplicationListener实现事件驱动架构
    • @EventListener注解简化观察者注册(如订单支付成功触发库存扣减)
  1. Android开发
    • LiveData组件通过观察者模式实现数据与UI的自动同步
    • OnClickListener等事件监听器机制
  1. GUI工具包
    • JavaFX的InvalidationListener(如表格数据变更触发图表重绘)
    • Qt框架的Signal/Slot机制(跨线程事件通知)
  1. 分布式系统
    • Redis的发布/订阅(Pub/Sub)消息模式
    • ZooKeeper的Watcher机制(节点变化通知)

五、模式优劣与最佳实践

优势

  • 松耦合架构:目标与观察者仅通过抽象接口交互,符合开闭原则
  • 实时响应能力:毫秒级状态同步(如股票行情实时刷新)

局限性

  • 通知顺序不可控:多个观察者的执行顺序可能影响系统行为
  • 循环触发风险:观察者修改目标状态可能引发无限循环

最佳实践

  1. 异步通知优化:结合线程池处理高并发场景(如电商大促期间订单通知)
  2. 状态过滤机制:仅在关键状态变化时触发通知(如温度变化超过1℃)
  3. 消息中间件集成:通过RabbitMQ等实现跨系统观察者模式

总结

观察者模式如同软件架构的"神经系统",通过事件驱动状态广播机制,在GUI开发、物联网、金融交易等场景中展现出强大的生命力。其设计精髓在于将状态生产者状态消费者解耦,开发者应重点把控通知粒度与性能平衡,结合具体场景选择同步/异步实现策略,从而构建出高响应、易扩展的现代化系统架构。

posted @ 2025-04-12 10:57  雾里看花的少年  阅读(29)  评论(0)    收藏  举报