观察者模式

点击阅读:设计模式系列文章


1. 观察者模式的定义

观察者模式 (Observer Pattern)是一种行为设计模式 ,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

观察者模式所做的工作就是在解除耦合。使耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化。

观察者模式解决了以下关键问题:

  • 状态同步难题:当多个对象需要同步状态时,避免硬编码的依赖关系
  • 动态订阅机制:运行时动态添加/移除观察者的能力
  • 事件驱动架构:构建响应式系统的基石

2. 观察者模式的结构

  1. Subject:抽象主题,一般为抽象类或接口,将所有的观察者引用存在一个集合里,并提供了增加和删除观察者对象的接口。
java 复制代码
public abstract class Subject {
    private List<Observer> observers = new ArrayList<>();
    

    private String state;
    
    public void setState(String state) {
        this.state = state;
        notifyObservers(); // 状态变更时通知观察者
    }
    
    public String getSubjectState(){
        return subjectState;
    }
    
    //添加观察者
    public void attach(Observer observer) {
        observers.add(observer);
    }

    //删除观察者
    public void detach(Observer observer) {
        observers.remove(observer);
    }

    //通知所有观察者
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}
  1. ConcreteSubject:具体主题,将有关联状态存入具体观察者对象。在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
java 复制代码
public class ConcreteSubject extends Subject {

}
  1. Observer:抽象观察者,一般为抽象类或接口,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。
java 复制代码
public interface Observer {
    void update();
}
  1. ConcreteObserver:具体观察者,实现具体观察者所要求的更新接口,以便使本身的状态与主题的状态相协调。
java 复制代码
public class ConcreteObserver implements Observer {
    private String name;
    private String subjectState;
    private Subject subject;

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

    @Override
    public void update() {
        subjectState = subject.getSubjectState();
        System.out.println("ConcreteObserver", "Observer " + name + ", state " + subjectState);
    }
}
  1. 客户端代码
java 复制代码
Subject subject = new ConcreteSubject();
subject.attach(new ConcreteObserver("Zhang San", subject));
subject.attach(new ConcreteObserver("Li Si", subject));
subject.attach(new ConcreteObserver("Wang Wu", subject));
subject.setSubjectState("Change");

3. 观察者模式 Java 内置接口的实现

Java 已经为观察者模式准备好了相关的接口和抽象类了。

java 复制代码
// 继承Observable类
class WeatherStation extends Observable {
    private float temperature;
    
    public void setTemperature(float temp) {
        this.temperature = temp;
        setChanged(); // 标记状态已改变
        notifyObservers(); // 通知观察者
    }
}

// 实现Observer接口
class PhoneDisplay implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof WeatherStation) {
            System.out.println("");
        }
    }
}

// 使用示例
WeatherStation station = new WeatherStation();
station.addObserver(new PhoneDisplay());
station.setTemperature(25.5f);

4. 观察者模式的优缺点

优点 :

  • 解耦设计:主题和观察者之间保持最小依赖
  • 动态扩展:无需修改主题即可增加新观察者
  • 事件驱动:支持分布式事件处理系统
  • 重用性高:主题和观察者可以独立复用

缺点 :

  • 通知顺序不可控:观察者接收通知的顺序不确定
  • 性能问题:大量观察者可能导致通知过程耗时
  • 循环依赖风险:不当实现可能导致循环调用

5. 观察者模式的相关实践

5.1 推拉模型

  • 推模型:主题主动将详细数据发送给观察者
  • 拉模型:观察者收到通知后主动从主题获取数据
java 复制代码
// 推模型实现
protected void notifyObservers(Object data) {
    for (Observer o : observers) {
        o.update(data); // 直接传递数据
    }
}

// 拉模型实现(推荐)
protected void notifyObservers() {
    for (Observer o : observers) {
        o.update(this); // 传递主题引用
    }
}

5.2 异步通知机制

线程安全优化,避免阻塞主题线程:

java 复制代码
public class ConcurrentSubject {
    private final CopyOnWriteArrayList<Observer> observers = 
        new CopyOnWriteArrayList<>();
    
    public void notifyObservers() {
        for (Observer o : observers) {
            // 使用线程池异步处理
            executorService.submit(() -> o.update(this));
        }
    }
}
相关推荐
拉不动的猪2 分钟前
安卓和ios小程序开发中的兼容性问题举例
前端·javascript·面试
胡侃有料1 小时前
【设计模式】1.简单工厂、工厂、抽象工厂模式
设计模式·抽象工厂模式
wandongle2 小时前
HTML面试整理
前端·面试·html
JiangJiang4 小时前
🔥 面试官:Webpack 为什么能热更新?你真讲得清吗?
前端·面试·webpack
~山有木兮5 小时前
C++设计模式 - 单例模式
c++·单例模式·设计模式
蒟蒻小袁5 小时前
力扣面试150题--被围绕的区域
leetcode·面试·深度优先
掘金安东尼5 小时前
字节-Trae、阿里-通义灵码、腾讯-CodeBuddy,为什么都在“卷”AI编码?
面试·llm·github
周某某~5 小时前
四.抽象工厂模式
java·设计模式·抽象工厂模式
spionbo6 小时前
Vue 表情包输入组件实现代码及完整开发流程解析
前端·javascript·面试