观察者模式是一种行为设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生变化时,其所有依赖者(观察者)都会收到通知并自动更新。在观察者模式中,主题(也称为可观察者或被观察者)维护着一组观察者,并在状态发生变化时通知它们。
-
结构
- 主题对象:也称为被观察者或者可观察对象,它维护了一组观察者对象,并提供了添加、删除和通知观察者的方法。主题对象的状态发生变化时,会通知所有注册的观察者。
- 观察者对象:观察者对象通过注册到主题对象上,以便在主题状态变化时接收通知。观察者对象通常定义了一个更新方法,用于接收主题对象发出的通知,并作出相应的更新。
- 一对多的依赖关系:观察者模式建立了一种一对多的依赖关系,一个主题对象可以有多个观察者对象,而每个观察者对象都只依赖于一个主题对象。
- 解耦:观察者模式将主题对象与观察者对象之间解耦,使得它们可以独立变化,而不会相互影响。这样可以降低系统的耦合度,提高代码的灵活性和可维护性。
- 动态变化:观察者模式允许动态地添加或删除观察者对象,而不需要修改主题对象的代码,使得系统更加灵活和可扩展。
-
优点
- 解耦:观察者模式将主题对象与观察者对象之间解耦,使得它们可以独立变化,而不会相互影响。
- 扩展性:可以随时添加或删除观察者对象,而不影响主题对象或其他观察者对象,使得系统更加灵活和可扩展。
- 通知机制:观察者模式提供了一种灵活的通知机制,可以实时地通知观察者对象主题状态的变化,从而实现更紧密的协作。
-
缺点
- 过多通知:如果主题对象的状态变化频繁,可能会导致观察者对象频繁地收到通知,造成性能上的开销。
- 循环依赖:如果观察者对象之间相互依赖,可能会导致循环依赖的问题,需要谨慎设计。
-
场景
- 事件处理:GUI编程中常用观察者模式处理用户界面组件的事件。
- 消息通知:发布/订阅模式是观察者模式的一种变体,常用于实现消息队列等系统。
- 状态监控:当需要监控对象的状态变化并作出相应响应时,观察者模式是一个常见的选择。
- 发布订阅系统:用于构建解耦的事件驱动架构,其中发布者和订阅者之间没有直接的依赖关系。
-
示例
import java.util.ArrayList;
import java.util.List;
// 主题接口(Subject Interface)
interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();
int getState();
}
// 具体主题类(Concrete Subject Class)
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
// 观察者接口(Observer Interface)
interface Observer {
void update();
}
// 具体观察者类(Concrete Observer Class)
class ConcreteObserver implements Observer {
private Subject subject;
public ConcreteObserver(Subject subject) {
this.subject = subject;
}
public void update() {
System.out.println("Observer received update. New state: " + subject.getState());
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
// 创建具体主题对象
ConcreteSubject subject = new ConcreteSubject();
// 创建具体观察者对象,并将主题对象注册为观察者
ConcreteObserver observer = new ConcreteObserver(subject);
subject.attach(observer);
// 改变主题对象的状态
subject.setState(10);
// 取消观察者的注册
subject.detach(observer);
// 再次改变主题对象的状态
subject.setState(20);
}
}
- 输出结果
Observer received update. New state: 10