观察者模式
什么是观察者模式?
观察者模式是一种行为型设计模式,用于建立对象间的一对多依赖关系。当一个对象(称为主题或发布者)的状态发生变化时,所有依赖它的对象(称为观察者或订阅者)会自动收到通知并更新。这种模式的核心思想是解耦,即主题和观察者之间不需要直接引用彼此,而是通过统一的接口进行通信。
核心角色
- Subject(主题/发布者)
- 维护观察者列表。
- 提供添加、删除观察者的方法。
- 定义通知观察者的方法(如
notify()
)。
- Observer(观察者/订阅者)
- 定义一个更新接口(如
update()
),用于接收主题的通知。 - 具体观察者实现该接口,定义具体的行为逻辑。
- 定义一个更新接口(如
- ConcreteSubject(具体主题)
- 存储具体的状态信息。
- 当状态变化时,触发通知所有观察者。
- ConcreteObserver(具体观察者)
- 实现
update()
方法,根据主题的状态变化执行具体操作。
- 实现
应用场景
- GUI事件处理
- 示例:按钮点击事件、窗口关闭事件等。
- 实现:通过
ActionListener
接口(Java Swing/AWT)或OnClickListener
(Android)传递事件信息。
- 实时数据监控与推送
- 示例:股票价格实时更新、传感器数据监控。
- 实现:主题(数据源)维护观察者列表,状态变化时广播通知。
- 事件驱动架构
- 示例:Spring 的
ApplicationEvent
和ApplicationListener
,Guava 的EventBus
。 - 实现:通过事件总线解耦组件间的通信。
- 示例:Spring 的
- 消息订阅系统
- 示例:新闻订阅、邮件通知。
- 实现:用户订阅特定主题,系统状态变化时推送消息。
示例:
主题/发布者
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点进行系统升级,请提前保存数据。