观察者模式 (Observer)
场景问题
问题案例
考虑一个微信公众号推送系统,用户可以订阅公众号,公众号发布新消息时,所有订阅用户都会收到通知。
不用模式的解决方案
实现简化版本
最直接的做法是公众号对象持有所有用户的引用,发布消息时遍历通知:
public class WeChatOfficialAccount {
private List<User> users = new ArrayList<>();
public void addUser(User user) { users.add(user); }
public void notifyUsers(String message) {
for (User u : users) {
u.receive(message);
}
}
}
public class User {
private String name;
public User(String name) { this.name = name; }
public void receive(String message) {
System.out.println(name + " 收到推送:" + message);
}
}
使用示例
WeChatOfficialAccount account = new WeChatOfficialAccount();
User u1 = new User("张三");
User u2 = new User("李四");
account.addUser(u1);
account.addUser(u2);
account.notifyUsers("新文章上线");
有何问题
- 用户和公众号耦合度高。
- 不能灵活扩展通知方式。
- 不能动态添加/移除观察者。
解决方案
观察者模式的定义
定义对象间一种一对多的依赖关系,使得每当一个对象状态发生变化时,其相关依赖对象都会收到通知并自动更新。
应用观察者模式的思路
- 定义抽象主题(Subject)和抽象观察者(Observer)接口。
- 主题对象维护观察者列表,状态变化时通知所有观察者。
- 观察者实现更新接口,接收通知。
观察者模式的结构
- Subject:抽象主题,定义维护观察者的方法。
- ConcreteSubject:具体主题,实现通知逻辑。
- Observer:抽象观察者,定义更新接口。
- ConcreteObserver:具体观察者,实现接收通知。
观察者模式的实现
// 抽象主题
public interface Subject {
void addObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers(String message);
}
// 具体主题
public class WeChatOfficialAccount implements Subject {
private List<Observer> users = new ArrayList<>();
public void addObserver(Observer o) { users.add(o); }
public void removeObserver(Observer o) { users.remove(o); }
public void notifyObservers(String message) {
for (Observer u : users) {
u.update(message);
}
}
}
// 抽象观察者
public interface Observer {
void update(String message);
}
// 具体观察者
public class User implements Observer {
private String name;
public User(String name) { this.name = name; }
public void update(String message) {
System.out.println(name + " 收到推送:" + message);
}
}
使用示例
public class Client {
public static void main(String[] args) {
WeChatOfficialAccount account = new WeChatOfficialAccount();
User u1 = new User("张三");
User u2 = new User("李四");
account.addObserver(u1);
account.addObserver(u2);
account.notifyObservers("新文章上线");
}
}
观察者重写示例
示例结构
示例代码
见上文"观察者模式的实现"部分。
模式讲解
观察者模式的功能
- 实现对象间的解耦。
- 支持动态添加、移除观察者。
- 便于扩展多种通知方式。
实现成接口
- 主题和观察者通常定义为接口或抽象类。
使用工厂方法
- 可结合工厂方法模式,统一创建主题和观察者对象。
切换产品簇
- 可用于切换不同的通知实现,如邮件、短信、推送等。