行为型:观察者模式

发布于:2025-05-30 ⋅ 阅读:(18) ⋅ 点赞:(0)

目录

1、核心思想

2、实现方式

2.1 模式结构

2.2 实现案例

3、优缺点分析

4、适用场景

5、注意事项


1、核心思想

目的:针对被观察对象与观察者对象之间一对多的依赖关系建立起一种行为自动触发机制,当被观察对象状态发生变化时主动对外发起广播,以通知所有观察者做出响应。核心目标是解耦主题与观察者。

举例

1> Websocket协议:不需要像Http轮询服务端的状态,服务端可以主动推送消息给客户端

2> 商店到货,通知购买者列表中的人来购物

2、实现方式

2.1 模式结构

四个核心角色:

  • Subject(目标主题)​:被观察的目标主题的接口抽象,维护观察者对象列表,并定义注册方法register()(订阅)与通知方法notify()(发布)​。
  • ConcreteSubject(主题实现)​:被观察的目标主题的具体实现类,持有一个属性状态State,维护观察者列表,并在状态变化时通知观察者。
  • Observer(观察者)​:观察者的接口抽象,定义响应方法update(),供主题调用。
  • ConcreteObserver(观察者实现)​:观察者的具体实现类,可以有任意多个子类实现。实现了响应方法update(),收到通知后进行自己独特的处理。

2.2 实现案例

当温度变化时,通知手机和电视更改温度显示:

//1、主题接口:注册、删除、通知观察者
public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

//2、主题实现:温度变化主题
public class WeatherStation implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private float temperature;

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

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

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

    @Override
    public void notifyObservers() {
        for (Observer o : observers) {
            o.update(temperature); // 推送数据给观察者
        }
    }
}

//3、观察者接口
public interface Observer {
    void update(float temperature);
}

//4、观察者实现:手机、电视
public class PhoneDisplay implements Observer {
    @Override
    public void update(float temperature) {
        System.out.println("手机显示温度更新:" + temperature + "℃");
    }
}

public class TVDisplay implements Observer {
    @Override
    public void update(float temperature) {
        System.out.println("电视显示温度更新:" + temperature + "℃");
    }
}

//5、客户端
public class Client {
    public static void main(String[] args) {
        WeatherStation station = new WeatherStation();
        PhoneDisplay phone = new PhoneDisplay();
        TVDisplay tv = new TVDisplay();

        // 注册观察者
        station.registerObserver(phone);
        station.registerObserver(tv);

        // 模拟温度变化
        station.setTemperature(25.5f); 
        // 输出:
        // 手机显示温度更新:25.5℃
        // 电视显示温度更新:25.5℃

        // 移除一个观察者
        station.removeObserver(tv);
        station.setTemperature(30.0f); 
        // 输出:手机显示温度更新:30.0℃
    }
}

两种数据传递方式:

  • 推模型(Push Model)

    主题主动将数据推送给观察者(如 update(temperature))。

  • 拉模型(Pull Model)

    观察者从主题拉取所需数据(如 update() 中调用 subject.getTemperature())。

3、优缺点分析

优点:

  • 解耦:主题与观察者无需知道彼此的具体实现。

  • 动态订阅:运行时动态添加或移除观察者。

  • 广播通信:支持一对多通知,适合事件驱动系统。

  • 遵循开闭原则:新增观察者无需修改主题代码。

缺点:

  • 通知顺序不可控:观察者更新顺序可能影响系统行为。

  • 性能问题:大量观察者或高频更新可能导致性能瓶颈。

  • 循环依赖风险:观察者与主题间不当引用可能导致死循环。

4、适用场景

  • 事件驱动系统

    • 如GUI按钮点击事件、消息队列通知。

  • 实时数据同步

    • 如股票价格变动通知、天气数据更新。

  • 跨模块状态同步

    • 如电商系统中库存变化触发订单状态更新。

  • 分布式系统

    • 如微服务架构中的配置中心推送更新。

5、注意事项

  • 避免内存泄漏

    观察者需及时取消注册(如Android中Activity销毁时移除监听)。

  • 线程安全

    多线程环境下需同步观察者列表(如使用 CopyOnWriteArrayList)。

  • 防止过度通知

    高频更新场景可采用批量通知或节流机制(如每秒最多通知一次)。


网站公告

今日签到

点亮在社区的每一天
去签到