引言
在软件开发中,设计模式是一种被广泛接受的、经过反复测试的、用于解决在特定环境下经常出现的特定问题的解决方案。观察者模式是其中的一种,它定义了对象之间的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。
在本文中,我们将探讨观察者模式在C语言中的应用。我们将首先介绍如何在不使用观察者模式的情况下解决问题,然后介绍如何使用观察者模式来改进我们的解决方案。我们还将讨论使用观察者模式的优点。
不使用观察者模式
假设我们正在开发一个气象站应用,这个应用需要从气象站获取实时的天气数据,并在多个显示设备上显示这些数据。如果不使用观察者模式,我们可能需要为每个显示设备创建一个单独的函数来获取和显示气象数据。以下是一个可能的实现:
#include <stdio.h>
// 定义气象数据的结构体
typedef struct {
float temperature;
float humidity;
float pressure;
} WeatherData;
// 更新并显示CurrentConditionsDisplay的数据
void update_current_conditions_display(WeatherData* weather_data) {
printf("Current conditions: %f F degrees and %f %% humidity and %f pressure\n", weather_data->temperature, weather_data->humidity, weather_data->pressure);
}
// 更新并显示ForecastDisplay的数据
void update_forecast_display(WeatherData* weather_data) {
printf("Forecast: Temperature: %f F degrees, Humidity: %f %%, Pressure: %f\n", weather_data->temperature, weather_data->humidity, weather_data->pressure);
}
// 设置WeatherData的测量值,并更新所有的显示设备
void set_measurements(WeatherData* weather_data, float temp, float humidity, float pressure) {
weather_data->temperature = temp;
weather_data->humidity = humidity;
weather_data->pressure = pressure;
update_current_conditions_display(weather_data);
update_forecast_display(weather_data);
}
int main() {
WeatherData weather_data;
set_measurements(&weather_data, 80, 65, 30.4f);
set_measurements(&weather_data, 82, 70, 29.2f);
return 0;
}
在这个代码中,我们没有使用观察者模式,而是直接在set_measurements
函数中调用了每个显示设备的更新函数。这样做的问题是,每当我们添加一个新的显示设备,我们都需要修改set_measurements
函数,这违反了开放封闭原则(软件实体应该对扩展开放,对修改封闭)。此外,这种方法也使得WeatherData
和显示设备之间的耦合度增加,这可能会导致代码更难维护和复用。
使用观察者模式
使用观察者模式可以避免上述问题。在观察者模式中,我们将创建两种类型的对象:观察者和被观察者。被观察者维护了一个观察者列表,并提供了添加(registerObserver
)、删除(removeObserver
)和通知(notifyObservers
)观察者的方法。当被观察者的状态发生变化时,它会通知所有的观察者。
观察者是一个接口,定义了一个update
方法,所有的观察者都需要实现这个方法,以便在被观察者状态变化时更新自己的状态。
以下是一个在C语言中使用观察者模式的示例:
#include <stdio.h>
#include <stdlib.h>
// 定义观察者的结构体
typedef struct {
void (*update)(float temp, float humidity, float pressure);
} Observer;
// 定义被观察者的结构体
typedef struct {
float temperature;
float humidity;
float pressure;
Observer* observer;
} WeatherData;
// CurrentConditionsDisplay的更新函数
void current_conditions_display_update(float temp, float humidity, float pressure) {
// 更新状态并显示
printf("Current conditions: %f F degrees and %f %% humidity and %f pressure\n", temp, humidity, pressure);
}
// 创建一个CurrentConditionsDisplay
Observer* create_current_conditions_display() {
Observer* observer = (Observer*)malloc(sizeof(Observer));
observer->update = current_conditions_display_update;
return observer;
}
// 设置WeatherData的测量值,并通知观察者
void set_measurements(WeatherData* weather_data, float temp, float humidity, float pressure) {
weather_data->temperature = temp;
weather_data->humidity = humidity;
weather_data->pressure = pressure;
weather_data->observer->update(temp, humidity, pressure);
}
int main() {
// 创建一个WeatherData和一个CurrentConditionsDisplay
WeatherData* weather_data = (WeatherData*)malloc(sizeof(WeatherData));
weather_data->observer = create_current_conditions_display();
// 改变WeatherData的状态
set_measurements(weather_data, 80, 65, 30.4f);
set_measurements(weather_data, 82, 70, 29.2f);
free(weather_data->observer);
free(weather_data);
return 0;
}
在这个代码中,我们创建了一个WeatherData
(被观察者)和一个CurrentConditionsDisplay
(观察者)。当WeatherData
的状态改变时,它会调用观察者的update
函数来更新观察者的状态。
为什么使用观察者模式
使用观察者模式有以下几个主要的好处:
-
解耦:观察者模式可以解耦观察者和被观察者之间的关系。在这种模式下,观察者和被观察者只需要知道对方实现了哪些接口,而不需要知道对方的具体实现。这使得观察者和被观察者可以独立地改变和复用。
-
动态关系:观察者模式允许在运行时动态地添加和删除观察者。这意味着我们可以在运行时改变被观察者和观察者之间的关系。
-
广播通信:被观察者会向所有的观察者广播通知,这使得观察者可以同时接收到通知,而不需要被观察者逐一通知每一个观察者。
以上就是观察者模式的基本概念和应用。希望这篇文章能帮助你理解和掌握观察者模式。创作不容易,请大家多多支持!非常感谢大家