大家好!今天我要和你们分享的是Java设计模式中的"明星选手"——观察者模式。🌟
作为一名多年的Java开发者,我不止一次地发现很多初学者在遇到"一个对象状态变化需要通知多个其他对象"的场景时,往往会写出大量重复且难以维护的代码。其实,这正是观察者模式大显身手的时刻!
1. 什么是观察者模式?
简单来说,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象。当主题对象状态发生变化时,它的所有依赖者(观察者)都会收到通知并自动更新。
想象一下订阅YouTube频道的场景:当UP主(主题)发布新视频时,所有订阅者(观察者)都会收到通知。这就是观察者模式的现实生活例子!👀
2. 观察者模式可视化
让我们通过UML类图来直观了解观察者模式的结构:
┌───────────┐ ┌───────────────┐
│ Subject │◇———————│ Observer │
├───────────┤ ├───────────────┤
│ observers │ │ update() │
├───────────┤ └───────────────┘
│ attach() │ ▲
│ detach() │ │
│ notify() │ ┌──────┴──────┐
└───────────┘ │ │
▲ ┌────┴───┐ ┌────┴───┐
│ │ConcreteA│ │ConcreteB│
┌─────┴──────┐ ├────────┤ ├────────┤
│ConcreteSubj│ │update()│ │update()│
├────────────┤ └────────┘ └────────┘
│getState() │
│setState() │
└────────────┘
这个图中的核心组件:
- Subject(主题): 持有观察者列表,提供添加、删除和通知观察者的方法
- Observer(观察者): 定义接收通知时需要执行的更新接口
- ConcreteSubject(具体主题): 实际的被观察对象,当状态变化时通知观察者
- ConcreteObserver(具体观察者): 实现Observer接口,在收到通知时执行特定操作
3. 观察者模式的Java实现
3.1 基础实现
让我们通过一个简单的例子来实现观察者模式:
// 观察者接口
public interface Observer {
void update(String message);
}
// 具体观察者
public class EmailNotifier implements Observer {
private String email;
public EmailNotifier(String email) {
this.email = email;
}
@Override
public void update(String message) {
System.out.println("发送邮件通知到 " + email + ": " + message);
}
}
// 主题接口
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体主题
public class NewsPublisher implements Subject {
private List<Observer> observers = new ArrayList<>();
private String latestNews;
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(latestNews);
}
}
// 当有新闻时调用此方法
public void publishNews(String news) {
this.latestNews = news;
notifyObservers();
}
}
3.2 使用Java内置的Observer接口
Java提供了内置的java.util.Observer
接口和java.util.Observable
类,虽然在Java 9中已被弃用,但了解它仍有帮助:
import java.util.Observable;
import java.util.Observer;
// 具体主题
public class WeatherStation extends Observable {
private float temperature;
public void setTemperature(float temperature) {
this.temperature = temperature;
setChanged(); // 标记状态已改变
notifyObservers(temperature); // 通知所有观察者
}
}
// 具体观察者
public class WeatherDisplay implements Observer {
@Override
public void update(Observable o, Object arg) {
if (arg instanceof Float) {
float temperature = (Float) arg;
System.out.println("温度更新为: " + temperature + "°C");
}
}
}
⚠️ 注意: java.util.Observer
和Observable
在Java 9中已被弃用,推荐使用自定义实现或其他替代方案。
3.3 使用Java事件模型
Java的事件模型实际上就是观察者模式的一种实现:
import java.util.EventObject;
import java.util.EventListener;
import java.util.ArrayList;
import java.util.List;
// 自定义事件
public class PriceChangeEvent extends EventObject {
private double newPrice;
public PriceChangeEvent(Object source, double newPrice) {
super(source);
this.newPrice = newPrice;
}
public double getNewPrice() {
return newPrice;
}
}
// 观察者接口
public interface PriceChangeListener extends EventListener {
void priceChanged(PriceChangeEvent event);
}
// 主题类
public class Product {
private String name;
private double price;
private List<PriceChangeListener> listeners = new ArrayList<>();
public Product(String name, double price) {
this.name = name;
this.price = price;
}
public void addPriceChangeListener(PriceChangeListener listener) {
listeners.add(listener);
}
public void removePriceChangeListener(PriceChangeListener listener) {
listeners.remove(listener);
}
public void setPrice(double newPrice) {
if (this.price != newPrice) {
double oldPrice = this.price;
this.price = newPrice;
// 创建事件对象并通知所有监听器
PriceChangeEvent event = new PriceChangeEvent(this, newPrice);
for (PriceChangeListener listener : listeners) {
listener.priceChanged(event);
}
}
}
}
4. Spring事件机制揭秘
Spring框架的事件处理系统是观察者模式的优秀实现!它允许组件之间的松耦合通信。🍃
4.1 Spring事件核心组件
Spring事件机制主要包含三个部分:
- 事件(Event): 继承自
ApplicationEvent
- 发布者(Publisher): 使用
ApplicationEventPublisher
发布事件 - 监听器(Listener): 实现
ApplicationListener
接口接收事件
4.2 实现示例
// 1. 自定义事件
public class UserRegisteredEvent extends ApplicationEvent {
private String username;
public UserRegisteredEvent(Object source, String username) {
super(source);
this.username = username;
}
public String getUsername() {
return username;
}
}
// 2. 事件监听器
@Component
public class WelcomeEmailListener implements ApplicationListener<UserRegisteredEvent> {
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
System.out.println("发送欢迎邮件给新用户: " + event.getUsername());
}
}
// 3. 事件发布
@Service
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public void registerUser(String username, String password) {
// 用户注册逻辑...
System.out.println("用户注册: " + username);
// 发布事件
eventPublisher.publishEvent(new UserRegisteredEvent(this, username));
}
}
4.3 使用注解简化
Spring 4.2之后,可以使用@EventListener
注解更优雅地实现事件监听:
@Component
public class NotificationService {
@EventListener
public void handleUserRegistration(UserRegisteredEvent event) {
System.out.println("发送欢迎邮件给: " + event.getUsername());
}
@EventListener
public void sendAdminAlert(UserRegisteredEvent event) {
System.out.println("通知管理员新用户注册: " + event.getUsername());
}
}
5. 观察者模式的应用场景
观察者模式在以下场景特别有用:
- UI界面更新: 当数据模型变化时更新视图
- 消息队列系统: 消费者订阅特定主题
- 系统监控: 在指标超过阈值时触发警报
- 事件驱动架构: 微服务间的解耦通信