观察者模式是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会得到通知并自动更新。观察者模式也被称为发布-订阅模式。
结构
- 主题(Subject): 维护一组观察者对象,提供注册和删除观察者的接口,以及通知观察者的方法。
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
- 具体主题(Concrete Subject): 实现主题接口,维护观察者列表,并在状态变化时通知观察者。
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private int state;
public void registerObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(state);
}
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
}
- 观察者(Observer): 定义了一个更新方法,用于接收主题的通知。
public interface Observer {
void update(int state);
}
- 具体观察者(Concrete Observer): 实现观察者接口,用于处理主题的通知。
public class ConcreteObserver implements Observer {
private int observerState;
public void update(int state) {
observerState = state;
System.out.println("Observer updated with state: " + observerState);
}
}
优点和缺点
优点:
- 松耦合: 观察者模式实现了主题和观察者之间的松耦合关系,主题不需要知道观察者的具体细节。
- 可扩展性: 可以很容易地增加或删除观察者,而不会影响主题的代码。
- 通知机制: 主题状态的变化会自动通知所有的观察者,确保观察者与主题状态保持同步。
缺点:
- 可能导致性能问题: 如果观察者很多,同时主题频繁变化,可能会导致性能问题。
- 可能引入循环依赖: 如果不小心设计,可能会出现观察者之间的循环依赖。
示例
以下是一个观察者模式的示例,模拟了一个气象站,主题对象为气象数据,观察者对象为显示器和日志记录器。
// 主题接口
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体主题 - 气象数据
public class WeatherData implements Subject {
private List<Observer> observers = new ArrayList<>();
private float temperature;
public void registerObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature);
}
}
public void setTemperature(float temperature) {
this.temperature = temperature;
notifyObservers();
}
}
// 观察者接口
public interface Observer {
void update(float temperature);
}
// 具体观察者 - 显示器
public class Display implements Observer {
public void update(float temperature) {
System.out.println("Display: Temperature is " + temperature);
}
}
// 具体观察者 - 日志记录器
public class Logger implements Observer {
public void update(float temperature) {
System.out.println("Logger: Logging temperature data: " + temperature);
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
Observer display = new Display();
Observer logger = new Logger();
weatherData.registerObserver(display);
weatherData.registerObserver(logger);
weatherData.setTemperature(25.5f); // 触发观察者更新
}
}
在这个示例中,WeatherData 是具体主题,维护观察者列表,当温度数据发生变化时,会通知所有观察者。Display 和 Logger 分别是具体观察者,它们实现了 Observer 接口,当收到通知时,会更新显示温度或记录温度日志。客户端代码创建了主题和观察者对象,并将观察者注册到主题上,当温度发生变化时,观察者会被自动通知。