Skip to content

观察者模式

什么是观察者模式?

观察者模式是一种行为型设计模式,用于建立对象间的一对多依赖关系。当一个对象(称为主题发布者)的状态发生变化时,所有依赖它的对象(称为观察者订阅者)会自动收到通知并更新。这种模式的核心思想是解耦,即主题和观察者之间不需要直接引用彼此,而是通过统一的接口进行通信。

核心角色

  1. Subject(主题/发布者)
    • 维护观察者列表。
    • 提供添加、删除观察者的方法。
    • 定义通知观察者的方法(如 notify())。
  2. Observer(观察者/订阅者)
    • 定义一个更新接口(如 update()),用于接收主题的通知。
    • 具体观察者实现该接口,定义具体的行为逻辑。
  3. ConcreteSubject(具体主题)
    • 存储具体的状态信息。
    • 当状态变化时,触发通知所有观察者。
  4. ConcreteObserver(具体观察者)
    • 实现 update() 方法,根据主题的状态变化执行具体操作。

应用场景

  1. GUI事件处理
    • 示例:按钮点击事件、窗口关闭事件等。
    • 实现:通过 ActionListener 接口(Java Swing/AWT)或 OnClickListener(Android)传递事件信息。
  2. 实时数据监控与推送
    • 示例:股票价格实时更新、传感器数据监控。
    • 实现:主题(数据源)维护观察者列表,状态变化时广播通知。
  3. 事件驱动架构
    • 示例:Spring 的 ApplicationEventApplicationListener,Guava 的 EventBus
    • 实现:通过事件总线解耦组件间的通信。
  4. 消息订阅系统
    • 示例:新闻订阅、邮件通知。
    • 实现:用户订阅特定主题,系统状态变化时推送消息。

示例:

主题/发布者

java
public interface Notice {
    /**
     * 发送通知
     *
     * @param message 通知内容
     */
    void send(String message);

    /**
     * 添加观察者
     *
     * @param observer 观察者
     */
    void addObserver(User observer);

    /**
     * 移除观察者
     *
     * @param observer 观察者
     */
    void removeObserver(User observer);
}
java
public class SysNotice implements Notice {
    private List<User> observers = new ArrayList<>(); // 观察者列表

    /**
     * 发送通知
     *
     * @param message 通知内容
     */
    @Override
    public void send(String message) {
        for (User observer : observers) {
            observer.update(message, "System");
        }
    }

    /**
     * 添加观察者
     *
     * @param observer 观察者
     */
    @Override
    public void addObserver(User observer) {
        observers.add(observer);
    }

    /**
     * 移除观察者
     *
     * @param observer 观察者
     */
    @Override
    public void removeObserver(User observer) {
        observers.remove(observer);
    }
}

观察者/订阅者

java
public interface User {
    /**
     * 接收通知
     *
     * @param message 通知内容
     * @param from    发送者
     */
    void update(String message, String from);


}
java
@Slf4j
public class CommonUser implements  User {
    private String name; // 用户名

    public CommonUser(String name) {
        this.name = name;
    }

    /**
     * 接收通知
     *
     * @param message 通知内容
     * @param from    发送者
     */
    @Override
    public void update(String message, String from) {
        log.info("用户 " + name + " 收到来自 " + from + " 的通知: " + message);
    }

    public String getName() {
        return name;
    }
}

调用

java
public class Main {
    public static void main(String[] args) {
        SysNotice sysNotice = new SysNotice();
        CommonUser user1 = new CommonUser("张三");
        CommonUser user2 = new CommonUser("李四");
        CommonUser user3 = new CommonUser("王五");
        sysNotice.addObserver(user1);
        sysNotice.addObserver(user2);
        sysNotice.addObserver(user3);

        // 发送通知
        sysNotice.send("系统维护通知:将于今晚12点进行系统升级,请提前保存数据。");
    }
}

输出:

bash
15:06:48.269 [main] INFO com.lj.observer.CommonUser -- 用户 张三 收到来自 System 的通知: 系统维护通知:将于今晚12点进行系统升级,请提前保存数据。
15:06:48.272 [main] INFO com.lj.observer.CommonUser -- 用户 李四 收到来自 System 的通知: 系统维护通知:将于今晚12点进行系统升级,请提前保存数据。
15:06:48.272 [main] INFO com.lj.observer.CommonUser -- 用户 王五 收到来自 System 的通知: 系统维护通知:将于今晚12点进行系统升级,请提前保存数据。
最近更新