tech-interview-for-developer:观察者模式实战-发布订阅事件驱动
🎯 读完本文你能得到什么?
- ✅ 观察者模式(Observer Pattern)的核心概念与设计原理
- ✅ 发布-订阅(Publish-Subscribe)机制的实现细节
- ✅ Java内置Observable类的实战应用与局限性
- ✅ 多线程环境下的观察者模式安全实现
- ✅ 真实业务场景中的观察者模式最佳实践
- ✅ 事件驱动架构的设计思路与性能优化
🔍 观察者模式:为什么它是现代软件架构的基石?
"你还在为组件间复杂的依赖关系而头疼吗?观察者模式让松耦合成为现实!"
观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会自动收到通知并更新。这种模式是事件驱动编程和响应式系统的核心基础。
📊 观察者模式 vs 发布订阅模式
| 特性 | 观察者模式 | 发布订阅模式 |
|---|---|---|
| 耦合度 | 相对紧耦合 | 完全解耦 |
| 通信方式 | 直接调用 | 通过消息代理 |
| 性能 | 同步,可能阻塞 | 异步,高性能 |
| 复杂度 | 简单易实现 | 需要中间件支持 |
🛠️ 核心组件与接口设计
1. 主题(Subject)接口
/**
* 主题接口 - 定义被观察对象的契约
*/
public interface Subject {
// 注册观察者
void registerObserver(Observer observer);
// 移除观察者
void removeObserver(Observer observer);
// 通知所有观察者
void notifyObservers();
// 设置状态变化(可选)
void setState(Object state);
// 获取当前状态(可选)
Object getState();
}
2. 观察者(Observer)接口
/**
* 观察者接口 - 定义观察者的更新行为
*/
public interface Observer {
// 当主题状态变化时被调用
void update(Subject subject, Object args);
// 获取观察者标识(用于去重等)
String getObserverId();
}
3. 具体主题实现
/**
* 新闻发布系统 - 具体主题实现
*/
public class NewsPublisher implements Subject {
private List<Observer> observers = new ArrayList<>();
private String latestNews;
private boolean changed = false;
@Override
public void registerObserver(Observer observer) {
if (!observers.contains(observer)) {
observers.add(observer);
System.out.println("观察者注册成功: " + observer.getObserverId());
}
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
System.out.println("观察者移除成功: " + observer.getObserverId());
}
@Override
public void notifyObservers() {
if (!changed) return;
List<Observer> observersLocal;
synchronized (this) {
observersLocal = new ArrayList<>(observers);
changed = false;
}
for (Observer observer : observersLocal) {
observer.update(this, latestNews);
}
}
public void publishNews(String news) {
this.latestNews = news;
this.changed = true;
notifyObservers();
}
// 线程安全的批量通知
public void publishNewsAsync(String news) {
this.latestNews = news;
this.changed = true;
new Thread(() -> {
notifyObservers();
}).start();
}
}
🎭 多种观察者实现策略
1. 邮件订阅观察者
public class EmailSubscriber implements Observer {
private String email;
private String subscriberId;
public EmailSubscriber(String email, String subscriberId) {
this.email = email;
this.subscriberId = subscriberId;
}
@Override
public void update(Subject subject, Object args) {
String news = (String) args;
System.out.println("发送邮件到 " + email + ": " + news);
// 实际发送邮件逻辑
sendEmail(news);
}
private void sendEmail(String content) {
// 模拟邮件发送
System.out.println("📧 邮件已发送: " + content.substring(0, Math.min(50, content.length())) + "...");
}
@Override
public String getObserverId() {
return "email-" + subscriberId;
}
}
2. 消息通知观察者
public class MessageSubscriber implements Observer {
private String contactInfo;
private String subscriberId;
public MessageSubscriber(String contactInfo, String subscriberId) {
this.contactInfo = contactInfo;
this.subscriberId = subscriberId;
}
@Override
public void update(Subject subject, Object args) {
String news = (String) args;
System.out.println("发送消息到 " + contactInfo + ": " + news);
sendMessage(news);
}
private void sendMessage(String content) {
// 模拟消息发送
System.out.println("📱 消息已发送: " + content.substring(0, Math.min(30, content.length())) + "...");
}
@Override
public String getObserverId() {
return "message-" + subscriberId;
}
}
3. 推送通知观察者
public class PushNotificationSubscriber implements Observer {
private String deviceId;
private String subscriberId;
public PushNotificationSubscriber(String deviceId, String subscriberId) {
this.deviceId = deviceId;
this.subscriberId = subscriberId;
}
@Override
public void update(Subject subject, Object args) {
String news = (String) args;
System.out.println("发送推送到设备 " + deviceId + ": " + news);
sendPushNotification(news);
}
private void sendPushNotification(String content) {
// 模拟推送通知
System.out.println("📲 推送通知已发送: " + content.substring(0, Math.min(40, content.length())) + "...");
}
@Override
public String getObserverId() {
return "push-" + subscriberId;
}
}
⚡ Java内置Observable类的实战应用
Java提供了内置的Observable类和Observer接口,但在实际项目中需要谨慎使用:
import java.util.Observable;
import java.util.Observer;
/**
* 使用Java内置Observable的新闻发布器
*/
public class JavaBuiltInNewsPublisher extends Observable {
private String news;
public void setNews(String news) {
this.news = news;
setChanged(); // 必须调用此方法
notifyObservers(news); // 通知所有观察者
}
public String getNews() {
return news;
}
}
/**
* 内置Observer接口的实现
*/
public class BuiltInNewsSubscriber implements Observer {
private String subscriberName;
public BuiltInNewsSubscriber(String subscriberName) {
this.subscriberName = subscriberName;
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof JavaBuiltInNewsPublisher) {
String news = (String) arg;
System.out.println(subscriberName + " 收到新闻: " + news);
}
}
}
⚠️ Java内置实现的局限性
- Observable是类而不是接口 - 限制了继承灵活性
- 没有线程安全保证 - 需要自行处理同步
- API设计较为陈旧 - 缺乏现代函数式编程支持
- setChanged()方法保护级别 - 限制了扩展性
🚀 高级特性与最佳实践
1. 事件对象封装
/**
* 新闻事件对象 - 封装事件详细信息
*/
public class NewsEvent {
private final String title;
private final String content;
private final Date publishTime;
private final String category;
private final int priority; // 优先级:1-高,2-中,3-低
public NewsEvent(String title, String content, String category, int priority) {
this.title = title;
this.content = content;
this.publishTime = new Date();
this.category = category;
this.priority = priority;
}
// Getter方法
public String getTitle() { return title; }
public String getContent() { return content; }
public Date getPublishTime() { return publishTime; }
public String getCategory() { return category; }
public int getPriority() { return priority; }
@Override
public String toString() {
return String.format("[%s] %s - %s", category, title,
content.substring(0, Math.min(50, content.length())));
}
}
2. 支持泛型的观察者接口
/**
* 泛型观察者接口 - 支持不同类型的事件
* @param <T> 事件类型
*/
public interface GenericObserver<T> {
void onEvent(T event);
String getObserverId();
boolean supportsEventType(Class<?> eventType);
}
/**
* 泛型主题接口
* @param <T> 事件类型
*/
public interface GenericSubject<T> {
void registerObserver(GenericObserver<T> observer);
void removeObserver(GenericObserver<T> observer);
void notifyObservers(T event);
void notifyObserversAsync(T event);
}
3. 基于优先级的事件分发
/**
* 支持优先级的事件分发器
*/
public class PriorityEventDispatcher implements GenericSubject<NewsEvent> {
private final Map<Integer, List<GenericObserver<NewsEvent>>> priorityObservers = new ConcurrentHashMap<>();
private final ExecutorService executor = Executors.newFixedThreadPool(4);
@Override
public void registerObserver(GenericObserver<NewsEvent> observer) {
// 根据观察者支持的事件类型分配优先级
int priority = determinePriority(observer);
priorityObservers.computeIfAbsent(priority, k -> new CopyOnWriteArrayList<>())
.add(observer);
}
private int determinePriority(GenericObserver<NewsEvent> observer) {
// 根据业务逻辑确定优先级
if (observer instanceof EmergencyNewsHandler) {
return 1; // 最高优先级
} else if (observer instanceof PremiumSubscriber) {
return 2; // 高优先级
}
return 3; // 普通优先级
}
@Override
public void notifyObservers(NewsEvent event) {
// 按优先级顺序通知
for (int priority = 1; priority <= 3; priority++) {
List<GenericObserver<NewsEvent>> observers = priorityObservers.get(priority);
if (observers != null) {
for (GenericObserver<NewsEvent> observer : observers) {
if (observer.supportsEventType(event.getClass())) {
observer.onEvent(event);
}
}
}
}
}
@Override
public void notifyObserversAsync(NewsEvent event) {
executor.submit(() -> notifyObservers(event));
}
// 其他方法实现...
}
🔧 多线程环境下的线程安全实现
1. 使用CopyOnWriteArrayList保证线程安全
public class ThreadSafeNewsPublisher implements Subject {
private final List<Observer> observers = new CopyOnWriteArrayList<>();
private volatile String latestNews;
private volatile boolean changed = false;
private final Object lock = new Object();
@Override
public void registerObserver(Observer observer) {
if (!observers.contains(observer)) {
observers.add(observer);
}
}
@Override
public void notifyObservers() {
if (!changed) return;
// 创建观察者列表的快照
List<Observer> observersSnapshot = new ArrayList<>(observers);
boolean currentChanged;
synchronized (lock) {
currentChanged = changed;
changed = false;
}
if (currentChanged) {
for (Observer observer : observersSnapshot) {
try {
observer.update(this, latestNews);
} catch (Exception e) {
// 处理单个观察者的异常,不影响其他观察者
System.err.println("观察者处理异常: " + e.getMessage());
}
}
}
}
}
2. 使用ReentrantReadWriteLock优化读写性能
public class OptimizedNewsPublisher implements Subject {
private final List<Observer> observers = new ArrayList<>();
private String latestNews;
private boolean changed = false;
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
@Override
public void registerObserver(Observer observer) {
rwLock.writeLock().lock();
try {
if (!observers.contains(observer)) {
observers.add(observer);
}
} finally {
rwLock.writeLock().unlock();
}
}
@Override
public void notifyObservers() {
List<Observer> observersSnapshot;
boolean currentChanged;
rwLock.readLock().lock();
try {
if (!changed) return;
observersSnapshot = new ArrayList<>(observers);
currentChanged = changed;
changed = false;
} finally {
rwLock.readLock().unlock();
}
if (currentChanged) {
for (Observer observer : observersSnapshot) {
observer.update(this, latestNews);
}
}
}
}
📈 性能优化与监控
1. 观察者执行时间监控
public class MonitoredObserver implements Observer {
private final Observer delegate;
private final String observerName;
private final MetricsCollector metrics;
public MonitoredObserver(Observer delegate, String observerName, MetricsCollector metrics) {
this.delegate = delegate;
this.observerName = observerName;
this.metrics = metrics;
}
@Override
public void update(Subject subject, Object args) {
long startTime = System.nanoTime();
try {
delegate.update(subject, args);
long duration = System.nanoTime() - startTime;
metrics.recordSuccess(observerName, duration);
} catch (Exception e) {
long duration = System.nanoTime() - startTime;
metrics.recordFailure(observerName, duration, e);
throw e;
}
}
@Override
public String getObserverId() {
return delegate.getObserverId();
}
}
2. 批量事件处理优化
public class BatchEventProcessor {
private final BlockingQueue<NewsEvent> eventQueue = new LinkedBlockingQueue<>();
private final ExecutorService processorThread;
private volatile boolean running = true;
private final List<GenericObserver<NewsEvent>> observers;
public BatchEventProcessor(List<GenericObserver<NewsEvent>> observers) {
this.observers = observers;
this.processorThread = Executors.newSingleThreadExecutor();
startProcessing();
}
public void submitEvent(NewsEvent event) {
eventQueue.offer(event);
}
private void startProcessing() {
processorThread.submit(() -> {
while (running || !eventQueue.isEmpty()) {
try {
List<NewsEvent> batch = new ArrayList<>();
// 批量获取事件(最多等待100ms或收集10个事件)
NewsEvent event = eventQueue.poll(100, TimeUnit.MILLISECONDS);
if (event != null) {
batch.add(event);
eventQueue.drainTo(batch, 9); // 再收集最多9个
}
if (!batch.isEmpty()) {
processBatch(batch);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
});
}
private void processBatch(List<NewsEvent> batch) {
for (GenericObserver<NewsEvent> observer : observers) {
for (NewsEvent event : batch) {
if (observer.supportsEventType(event.getClass())) {
observer.onEvent(event);
}
}
}
}
public void shutdown() {
running = false;
processorThread.shutdown();
}
}
🎯 真实业务场景应用
1. 电商订单状态通知系统
2. 微服务架构中的事件驱动
/**
* 分布式事件发布器 - 支持跨服务事件通知
*/
public class DistributedEventPublisher implements Subject {
private final List<Observer> localObservers = new CopyOnWriteArrayList<>();
private final MessageQueueClient mqClient;
private final String serviceName;
public DistributedEventPublisher(MessageQueueClient mqClient, String serviceName) {
this.mqClient = mqClient;
this.serviceName = serviceName;
}
@Override
public void notifyObservers() {
// 本地观察者通知
for (Observer observer : localObservers) {
observer.update(this, null);
}
// 分布式事件发布
DistributedEvent event = createDistributedEvent();
mqClient.publish(event);
}
private DistributedEvent createDistributedEvent() {
return new DistributedEvent(
serviceName,
"STATE_CHANGE",
System.currentTimeMillis(),
Collections.singletonMap("state", getState())
);
}
// 处理来自其他服务的远程事件
public void handleRemoteEvent(DistributedEvent event) {
if (!event.getSourceService().equals(serviceName)) {
setState(event.getPayload().get("
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



