目录
1、简介
观察者模式是一种软件设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象,当主题对象发生变化时,所有的观察者对象都会得到通知并且自动更新。
2、组成部分
观察者模式中的三个核心角色包括:
- 主题(Subject):被观察的对象,通常会维护一个观察者列表,以便在状态发生变化时通知观察者。
- 观察者(Observer):观察主题对象的状态变化,当主题状态发生变化时,观察者将得到通知并执行相应的操作。
- 具体主题(ConcreteSubject):具体的主题实现类,负责维护一个观察者列表,并实现主题对象状态变化的通知逻辑。
- 具体观察者(ConcreteObserver):具体的观察者实现类,实现观察者接口,并定义观察者接收到通知后的具体操作。
3、优缺点
观察者模式的优点包括:
- 降低对象之间的耦合性:主题对象和观察者对象之间的关系是松散的,它们之间并没有直接依赖关系,使得它们之间的交互变得灵活和可扩展。
- 符合“开闭原则”:当需要增加新的观察者对象时,不需要修改主题对象的代码,只需要增加一个新的具体观察者即可。
- 支持广播通信:主题对象可以同时通知多个观察者对象,使得多个观察者对象可以同时对主题对象的状态变化进行响应。
观察者模式的缺点包括:
- 观察者数量过多会导致性能问题:如果观察者数量过多,每次状态变化都需要通知所有的观察者对象,会导致性能问题。
- 观察者与主题的依赖关系可能会导致循环引用:观察者对象和主题对象之间是相互依赖的,如果设计不当可能会导致循环引用问题。
- 可能会出现状态不一致问题:如果观察者对象在收到通知后执行的操作与主题对象的状态更新操作不同步,可能会导致观察者对象的状态与主题对象的状态不一致。
- 观察者对象接收到的通知是有序的:通知的顺序可能会影响观察者对象的执行结果,如果观察者对象之间有相互依赖关系,可能会影响整个系统的正确性。
- 观察者模式可能会导致性能问题题:如果主题对象在通知观察者对象时,需要执行较为复杂的操作,可能会影响整个系统的性能。
总体来说,观察者模式是一种很有用的设计模式,它可以实现对象之间的松耦合,提高代码的可维护性和可扩展性。但是在使用时需要注意上述缺点,并结合具体的业务场景进行选择。
4、使用场景
观察者模式的使用场景包括:
- 一个对象的状态变化会影响其他对象:当一个对象的状态发生变化时,其他多个对象需要做出相应的响应,此时可以使用观察者模式。
- 对象的状态更新频繁且多个对象需要及时更新:如果一个对象的状态更新非常频繁,多个对象需要及时更新状态,那么使用观察者模式可以提高程序的效率。
- 对象需要在不同的情况下通知不同的观察者对象:当对象需要在不同的情况下通知不同的观察者对象时,可以使用观察者模式。这种情况下,每个观察者对象只需要关注它所感兴趣的通知即可。
- 想要实现事件监听器:当需要在程序中实现事件监听器时,可以使用观察者模式。例如,在Java中,可以使用Swing框架中的观察者模式来实现图形界面组件的事件监听器。
- MVC模式中的视图与模型:在MVC(Model-View-Controller)模式中,视图层需要对模型层进行监听,当模型层发生变化时,视图层需要及时更新自己的显示。此时可以使用观察者模式,将视图层作为观察者对象,将模型层作为主题对象。
总之,当需要在多个对象之间实现松耦合的消息传递时,可以考虑使用观察者模式。观察者模式适用于需要动态更新的场景,可以帮助我们将代码设计得更加灵活和可扩展。
5、代码实现
下面是一个使用Java实现观察者模式的示例,并对代码进行详细说明:
1、首先定义主题接口Subject和观察者接口Observer:
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
public interface Observer {
void update(float temperature, float humidity, float pressure);
}
2、定义具体的主题类WeatherData,实现Subject接口:
import java.util.ArrayList;
public class WeatherData implements Subject {
private ArrayList<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<>();
}
public void registerObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
int index = observers.indexOf(observer);
if (index >= 0) {
observers.remove(index);
}
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
public void measurementsChanged() {
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
3、定义具体的观察者类CurrentConditionsDisplay,实现Observer接口:
public class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
private float pressure;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
display();
}
public void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
}
}
4、编写测试代码:
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}
运行以上代码,输出结果如下:
Current conditions: 80.0F degrees and 65.0% humidity
Current conditions: 82.0F degrees and 70.0% humidity
Current conditions: 78.0F degrees and 90.0% humidity
以上代码演示了观察者模式的基本实现,具体说明如下:
- WeatherData类是主题类,它维护了一个观察者列表,实现了Subject接口中的三个方法:registerObserver、removeObserver和notifyObservers,用来注册观察者、移除观察者和通知观察者。WeatherData类还定义了一个measurementsChanged方法,用来在气象数据发生变化时通知观察者。
- CurrentConditionsDisplay类是观察者类,它实现了Observer接口中的update方法,用来更新观测值,并调用display方法展示当前观测值。CurrentConditionsDisplay类还在构造方法中注册到主题类中,以便接收气象数据的变化通知。
- WeatherStation类是测试类,创建了WeatherData和CurrentConditionsDisplay对象,并通过调用setMeasurements方法模拟气象数据的变化,然后观察当前观测值是否会被更新和显示出来。
观察者模式的实现可以让主题类和观察者类分离,使它们之间的依赖性降到最低,提高了代码的灵活性和可扩展性。当主题对象发生变化时,所有注册的观察者对象都会收到通知,可以进行相应的处理,实现了松耦合。
需要注意的是,观察者模式也存在一些缺点。当观察者对象较多时,主题对象的通知会导致较大的开销;观察者对象需要实现update方法,这可能会导致代码的复杂性增加。因此,在使用观察者模式时需要根据具体情况进行权衡和选择。