观察者模式(Observer Pattern)
观察者模式(Observer Pattern)
观察者模式是一种行为型设计模式,它定义了对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会自动收到通知并更新。观察者模式也被称为发布-订阅模式,它允许对象之间松耦合地交互。
模式结构
- 发布者接口(Publisher)
定义订阅、取消订阅和通知观察者的方法。 - 具体发布者(Concrete Publisher)
实现发布者接口,负责维护观察者列表,并在状态改变时通知所有观察者。 - 观察者接口(Observer)
定义更新方法,观察者通过该方法接收发布者的通知。 - 具体观察者(Concrete Observer)
实现观察者接口,负责在接收到通知时执行相应的操作。 - 客户端(Client)
创建发布者和观察者对象,并将观察者注册到发布者中。
代码示例
1. 发布者接口(Publisher)
// 发布者接口:定义订阅、取消订阅和通知观察者的方法
interface Publisher {
void subscribe(Observer observer);
void unSubscribe(Observer observer);
void notifySubscribers();
Object update(Observer observer);
}
2. 具体发布者(Concrete Publisher)
// 具体发布者:实现发布者接口
class MessageCenter implements Publisher {
private final List<Observer> observers;
private String message;
private Boolean changed;
private final Object SEM = new Object();
public MessageCenter() {
this.observers = new ArrayList<>();
}
@Override
public void subscribe(Observer observer) {
synchronized (SEM) {
if (!observers.contains(observer)) {
observers.add(observer);
}
}
}
@Override
public void unSubscribe(Observer observer) {
synchronized (SEM) {
observers.remove(observer);
}
}
@Override
public void notifySubscribers() {
List<Observer> localObservers;
synchronized (SEM) {
if (!changed) {
return;
}
localObservers = new ArrayList<>(this.observers);
this.changed = false;
}
for (Observer observer : localObservers) {
observer.update();
}
}
@Override
public Object update(Observer observer) {
return this.message;
}
public void postMessage(String message) {
System.out.println("Message Center Posted : " + message);
this.message = message;
this.changed = true;
notifySubscribers();
}
}
3. 观察者接口(Observer)
// 观察者接口:定义更新方法
interface Observer {
void update();
void bind(Publisher publisher);
}
4. 具体观察者(Concrete Observer)
// 具体观察者:实现观察者接口
class MessageSubscriber implements Observer {
private String name;
private Publisher publisher;
public MessageSubscriber(String name) {
this.name = name;
}
@Override
public void update() {
String message = (String) publisher.update(this);
if (message != null) {
System.out.println("[" + name + "] Consuming message : " + message);
} else {
System.out.println("[" + name + "] No new message");
}
}
@Override
public void bind(Publisher publisher) {
this.publisher = publisher;
}
}
5.调用示例
public class ObserverPattern {
public static void main(String[] args) {
MessageCenter messageCenter = new MessageCenter();
Observer observer1 = new MessageSubscriber("Jack");
Observer observer2 = new MessageSubscriber("Tom");
Observer observer3 = new MessageSubscriber("Mike");
messageCenter.subscribe(observer1);
messageCenter.subscribe(observer2);
messageCenter.subscribe(observer3);
observer1.bind(messageCenter);
observer2.bind(messageCenter);
observer3.bind(messageCenter);
observer1.update();
messageCenter.postMessage("How are you feeling today?");
}
}
输出结果
[Jack] No new message
Message Center Posted : How are you feeling today?
[Jack] Consuming message : How are you feeling today?
[Tom] Consuming message : How are you feeling today?
[Mike] Consuming message : How are you feeling today?
应用场景
- 一对多的依赖关系
当一个对象的状态改变需要通知多个其他对象时,可以使用观察者模式。例如,消息发布系统、事件处理系统等。 - 动态订阅机制
当需要在运行时动态地添加或移除观察者时,可以使用观察者模式。观察者模式允许观察者随时加入或离开发布者的订阅列表。 - 解耦发布者和观察者
当需要将发布者和观察者解耦,使得它们可以独立变化时,可以使用观察者模式。
在Java中的应用
java.util.Observer
和java.util.Observable
Java 提供了Observer
接口和Observable
类来实现观察者模式。尽管这些类在 Java 9 中被标记为过时,但它们仍然是观察者模式的经典实现。- 事件监听机制
Java 的 GUI 框架(如 Swing 和 JavaFX)广泛使用了观察者模式来处理用户事件(如按钮点击、鼠标移动等)。
优缺点
优点
- 解耦发布者和观察者
观察者模式将发布者和观察者解耦,使得它们可以独立变化。 - 动态订阅机制
观察者模式允许在运行时动态地添加或移除观察者,增加了系统的灵活性。 - 支持广播通信
观察者模式支持一对多的通信方式,发布者可以同时通知多个观察者。
缺点
- 通知顺序不确定
观察者模式中,观察者被通知的顺序是不确定的,可能会导致一些难以调试的问题。 - 性能问题
如果观察者数量过多,或者观察者的更新操作非常耗时,可能会导致性能问题。
总结
观察者模式通过定义对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会自动收到通知并更新。它适用于需要解耦发布者和观察者、支持动态订阅机制或广播通信的场景。尽管它可能会带来通知顺序不确定和性能问题,但其优点在于提高了系统的灵活性和可扩展性。在Java中,观察者模式广泛应用于事件处理和GUI框架等场景。