设计模式之观察者模式
·
1. 什么是观察者模式
观察者模式(Observer Pattern)是一种 行为型设计模式,用于建立对象之间的 一对多依赖关系,当一个对象(Subject,主题/被观察者)状态改变时,所有依赖它的对象(Observers,观察者)会自动收到通知并更新。
2. 优点和缺点
✅ 优点
1. 松耦合(Low Coupling)
-
主题(Subject) 和 观察者(Observer) 之间仅通过抽象接口交互,彼此不知道具体实现。
-
符合 依赖倒置原则(DIP),依赖抽象而非具体实现。
2. 动态订阅机制
-
观察者可以 运行时动态注册/注销,灵活性高。
-
例如:GUI 按钮可以随时添加或移除点击事件监听器。
3. 一对多通信
-
一个主题状态变化可自动通知 多个观察者,无需手动遍历调用。
-
适用于广播场景(如股票价格变动通知多个交易终端)。
4. 开闭原则支持
-
新增观察者无需修改主题代码(只需注册)。
-
扩展性强,适合需求频繁变化的系统。
❌ 缺点
1. 意外更新(Unintended Updates)
-
观察者可能收到 不必要或冗余的通知(如主题频繁触发但状态未实际变化)。
-
解决方案:引入
dirty标志或差分通知(仅发送变化部分)。
2. 性能问题
-
观察者数量多时,遍历通知所有观察者 可能成为性能瓶颈。
-
解决方案:异步通知(如用线程池)或按优先级分批通知。
3. 内存泄漏风险
-
如果观察者未正确注销,主题会持有观察者的引用,导致 对象无法被垃圾回收。
-
解决方案:使用弱引用(
WeakReference)或显式注销机制。
4. 调试困难
-
通知链可能形成 复杂的调用路径,导致问题难以追踪。
-
解决方案:添加日志或使用事件总线(如 EventBus)管理流程。
3. 应用场景
| 场景 | 说明 |
|---|---|
| GUI 事件处理 | 按钮点击、键盘输入等事件监听。 |
| 发布-订阅系统 | Kafka、Redis Pub/Sub 等消息队列。 |
| MVC 架构 | 模型(Model)变更时自动更新视图(View)。 |
| 游戏开发 | 角色血量变化触发 UI、音效、成就系统等多方响应 |
4. Java代码示例
// 主题接口
public interface Subject {
/**
* 注册一个观察者
*/
void registerObserver(Observer observer);
/**
* 移除一个观察者
*/
void removeObserver(Observer observer);
/**
* 通知所有观察者
*/
void notifyObservers();
}
//观察者接口
public interface Observer {
void update(String name,String age,String number);
}
//主题实现类
public class School implements Subject{
private String name;
private String age;
private String number;
private List<Observer> school;
public School(){
school = new CopyOnWriteArrayList<>();
}
@Override
public void registerObserver(Observer o) {
school.add(o);
}
@Override
public void removeObserver(Observer o) {
school.remove(o);
}
@Override
public void notifyObserver() {
for (Observer observer : school) {
observer.update(name,age,number);
}
}
public void setSchool(String name,String age,String number){
this.name = name;
this.age = age;
this.number = number;
notifyObserver();
}
}
//观察者实现类
public class Display implements Observer{
private String name;
private String age;
private String number;
private Subject school;
public Display(Subject school){
this.school = school;
school.registerObserver(this);
}
@Override
public void update(String name, String age, String number) {
this.name = name;
this.age = age;
this.number = number;
display();
}
private void display() {
System.out.println("姓名:"+name+",年龄:"+age+",工号:"+number);
}
}
//测试
public static void main(String[] args) {
School school = new School();
Display display = new Display(school);
school.setSchool("张三","22","n1");
school.setSchool("张三","23","n2");
school.setSchool("张三","24","n3");
}

运行结果
更多推荐


所有评论(0)