小易说IT 小易说IT

Java 观察者模式(Observer)示例代码

观察者模式:一个被观察者(主题)状态变化,自动通知所有注册的观察者,触发更新,属于行为型设计模式。

JDK 原生也提供 java.util.Observer / Observable,不过已经标记废弃,下面手写一套标准实现,便于理解原理。

UML 角色

  1. Subject(抽象主题 / 被观察者):注册、移除、通知观察者

  2. ConcreteSubject(具体被观察者):维护状态,状态改变时发起通知

  3. Observer(抽象观察者):接收更新回调接口

  4. ConcreteObserver(具体观察者):实现更新逻辑

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

/**
 * 抽象观察者接口
 */
interface Observer {
    /**
     * 被观察者通知时调用
     * @param message 通知消息
     */
    void update(String message);
}

/**
 * 抽象被观察者(主题)
 */
abstract class Subject {
    // 保存已注册观察者
    protected final List<Observer> observerList = new ArrayList<>();

    // 注册观察者
    public void attach(Observer observer) {
        observerList.add(observer);
    }

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

    // 通知所有观察者
    public abstract void notifyObservers();
}

/**
 * 具体被观察者:消息发布者
 */
class MessageSubject extends Subject {
    private String message;

    public void setMessage(String message) {
        this.message = message;
        // 状态变更,推送通知
        notifyObservers();
    }

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

/**
 * 具体观察者A:用户A
 */
class UserObserverA implements Observer {
    private final String name;

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

    @Override
    public void update(String message) {
        System.out.printf("[%s] 收到消息通知:%s%n", name, message);
    }
}

/**
 * 具体观察者B:用户B
 */
class UserObserverB implements Observer {
    private final String name;

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

    @Override
    public void update(String message) {
        System.out.printf("[%s] 收到消息通知:%s%n", name, message);
    }
}

// 测试主类
public class ObserverDemo {
    public static void main(String[] args) {
        // 创建被观察者
        MessageSubject subject = new MessageSubject();

        // 创建观察者
        Observer userA = new UserObserverA("张三");
        Observer userB = new UserObserverB("李四");

        // 订阅(注册)
        subject.attach(userA);
        subject.attach(userB);

        System.out.println("===== 第一次消息推送 =====");
        subject.setMessage("系统发布新版本V2.0");

        // 取消订阅张三
        subject.detach(userA);
        System.out.println("\n===== 第二次消息推送(张三已取消订阅) =====");
        subject.setMessage("服务器即将维护升级");
    }
}

输出结果

===== 第一次消息推送 =====
[张三] 收到消息通知:系统发布新版本V2.0
[李四] 收到消息通知:系统发布新版本V2.0

===== 第二次消息推送(张三已取消订阅) =====
[李四] 收到消息通知:服务器即将维护升级

JDK 废弃 API 版本(了解即可,不推荐新项目使用)

java.util.Observablejava.util.Observer Java9+ @Deprecated

import java.util.Observable;
import java.util.Observer;

// 被观察者
class JdkSubject extends Observable {
    public void publish(String msg) {
        setChanged(); // 标记状态发生改变,必须调用
        notifyObservers(msg);
    }
}

public class JdkObserverDemo {
    public static void main(String[] args) {
        JdkSubject subject = new JdkSubject();
        Observer obs = (o, arg) -> System.out.println("收到:" + arg);
        subject.addObserver(obs);
        subject.publish("jdk观察者消息");
    }
}

缺点:Observable 是类不是接口,Java 单继承限制,灵活性差,所以废弃。生产项目建议手写自定义接口方式

观察者模式优缺点

✅ 优点

  1. 观察者与被观察者松耦合,互不依赖具体实现

  2. 支持一对多广播通知,新增观察者不用修改主题代码,符合开闭原则

❌ 缺点

  1. 观察者过多,通知广播耗时;同步阻塞模式下某个观察者卡顿会影响全部通知

  2. 没有顺序保障,观察者执行顺序不可控;容易出现循环调用问题

常见业务场景

  • 事件订阅:消息推送、事件总线

  • GUI 事件监听

  • MQ 消息消费、配置变更推送

  • Spring 的 ApplicationListener 事件机制底层就是观察者模式


本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。

原文链接 https://www.yijunzhao.cc/archives/java-observer-pattern-example-code

欢迎访问 https://www.yijunzhao.cc/

https://www.yijunzhao.cc/