java泛型观察者模式通过将事件类型作为泛型参数绑定到event、observer和subject,实现类型安全的事件监听,避免强制转换。具体包括:泛型event类封装事件数据;observer接口约束监听事件类型;subject专注单一事件类型并管理对应观察者列表;使用时类型自动对齐,编译期校验。

Java 中用泛型实现观察者模式,核心是让观察者能监听任意类型事件,同时避免强制类型转换、提升类型安全。关键在于把事件类型作为泛型参数绑定到观察者和被观察者上。
定义泛型事件类
事件对象本身应是泛型的,便于携带任意数据:
- 不继承任何框架类,保持轻量;
- 可包含时间戳、来源对象、业务数据等通用字段;
- 泛型参数 E 表示具体事件内容类型。
public class Event<e> {
private final long timestamp;
private final Object source;
private final E data;
public Event(Object source, E data) {
this.timestamp = System.currentTimeMillis();
this.source = source;
this.data = data;
}
public long getTimestamp() { return timestamp; }
public Object getSource() { return source; }
public E getData() { return data; }
}</e>
泛型观察者接口
观察者只关心自己能处理的事件类型,用泛型约束 onEvent 方法参数:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 接口声明为 Observer
,E 即它期望接收的事件数据类型; - 避免在实现类中做
(MyEvent) event.getData()这类手动转型; - 一个观察者可监听多种事件,就需多个泛型实现(如
Observer<userloginevent></userloginevent>和Observer<orderpaidevent></orderpaidevent>)。
public interface Observer<e> {
void onEvent(Event<e> event);
}</e></e>
泛型被观察者(事件发布器)
被观察者内部维护不同类型事件的观察者集合,按事件类型分组管理:
- 用 Map
, List 存储,但注意通配符带来的类型擦除问题;>> - 更稳妥做法是用 Map
, List> + 运行时类型检查,或引入类型令牌(TypeToken); - 推荐简化版:每个被观察者专注一种事件类型,声明为 Subject
,内部只存 List<observer>></observer>; - 触发通知时,直接遍历同类型观察者,编译期保证类型匹配。
public class Subject<e> {
private final List<observer>> observers = new ArrayList();
public void addObserver(Observer<e> observer) {
observers.add(observer);
}
public void removeObserver(Observer<e> observer) {
observers.remove(observer);
}
public void notifyObservers(E data) {
Event<e> event = new Event(this, data);
observers.forEach(observer -> observer.onEvent(event));
}
}</e></e></e></observer></e>
使用示例:用户登录事件监听
定义具体事件类型与观察者,类型自动对齐:
-
UserLoginEvent是普通 POJO; -
LoginLogger实现Observer<userloginevent></userloginevent>,方法参数天然就是UserLoginEvent; - 注册和触发都无需 cast,IDE 能提示、编译器会校验。
public class UserLoginEvent {
private final String username;
public UserLoginEvent(String username) { this.username = username; }
// getter...
}
public class LoginLogger implements Observer<userloginevent> {
@Override
public void onEvent(Event<userloginevent> event) {
System.out.println("User logged in: " + event.getData().getUsername());
}
}
// 使用
Subject<userloginevent> loginSubject = new Subject();
loginSubject.addObserver(new LoginLogger());
loginSubject.notifyObservers(new UserLoginEvent("alice"));</userloginevent></userloginevent></userloginevent>
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










