1.简介
观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。这种模式在很多场景下都非常有用,比如在GUI应用中,用户界面组件通常需要响应数据模型中的变化。
2.通俗讲解
假设有一个天气预报系统,其中包括一个气象站(Subject)和多个观察者(Observers)。气象站负责收集数据(如温度、湿度等),而观察者则根据这些数据做出相应的反应(如显示在不同的设备上)。
3.实战
首先,我们需要定义一些基本的数据结构:
- Subject —— 气象站,用于存储数据和管理观察者列表。
- Observer —— 观察者,用于接收数据更新的通知。
3.1.代码
#include <stdio.h>
#include <stdlib.h>
// 定义观察者结构体
typedef struct Observer {
void (*update)(int temp, int humidity); // 更新函数指针
char *name; // 观察者的名称
} Observer;
// 定义主体结构体
typedef struct Subject {
int temperature; // 温度
int humidity; // 湿度
Observer **observers; // 观察者数组
int numObservers; // 当前观察者的数量
} Subject;
// 创建新的观察者
Observer *createObserver(char *name, void (*updateFunc)(int, int)) {
Observer *observer = (Observer *)malloc(sizeof(Observer));
observer->name = name;
observer->update = updateFunc;
return observer;
}
// 创建新的主题
Subject *createSubject() {
Subject *subject = (Subject *)malloc(sizeof(Subject));
subject->temperature = 0;
subject->humidity = 0;
subject->numObservers = 0;
subject->observers = NULL;
return subject;
}
// 添加观察者到主题
void attach(Subject *subject, Observer *observer) {
subject->observers = (Observer **)realloc(subject->observers, sizeof(Observer *) * (subject->numObservers + 1));
subject->observers[subject->numObservers++] = observer;
}
// 移除观察者
void detach(Subject *subject, Observer *observer) {
int i;
for (i = 0; i < subject->numObservers; i++) {
if (subject->observers[i] == observer) {
break;
}
}
if (i < subject->numObservers) {
subject->numObservers--;
subject->observers[i] = subject->observers[subject->numObservers];
subject->observers = (Observer **)realloc(subject->observers, sizeof(Observer *) * subject->numObservers);
}
}
// 通知所有观察者
void notify(Subject *subject) {
int i;
for (i = 0; i < subject->numObservers; i++) {
Observer *observer = subject->observers[i];
observer->update(subject->temperature, subject->humidity);
}
}
// 设置数据
void setData(Subject *subject, int temperature, int humidity) {
subject->temperature = temperature;
subject->humidity = humidity;
notify(subject);
}
// 更新函数示例
void updateTemperature(int temp, int humidity) {
printf("Temperature Observer: Temperature is now %d, Humidity is %d\n", temp, humidity);
}
void updateHumidity(int temp, int humidity) {
printf("Humidity Observer: Temperature is now %d, Humidity is %d\n", temp, humidity);
}
int main() {
Subject *weatherStation = createSubject();
Observer *temperatureObserver = createObserver("Temperature Observer", updateTemperature);
Observer *humidityObserver = createObserver("Humidity Observer", updateHumidity);
attach(weatherStation, temperatureObserver);
attach(weatherStation, humidityObserver);
setData(weatherStation, 25, 60);
setData(weatherStation, 23, 65);
detach(weatherStation, temperatureObserver);
setData(weatherStation, 22, 70);
free(temperatureObserver);
free(humidityObserver);
free(weatherStation->observers);
free(weatherStation);
return 0;
}
3.2.代码解析
- Observer 结构体包含了更新函数指针和观察者的名称。
- Subject 结构体包含了温度、湿度以及观察者数组。
attach
和detach
函数分别用来添加和移除观察者。notify
函数循环调用每个观察者的更新函数。setData
函数设置新数据,并通知所有观察者。
3.3.代码运行
- 创建一个气象站
weatherStation
。 - 创建两个观察者:
temperatureObserver
和humidityObserver
,分别关注温度和湿度的变化。 - 将这两个观察者添加到气象站中。
- 更新气象站的数据,并通知所有观察者。
- 移除其中一个观察者(例如
temperatureObserver
),再次更新数据并通知剩余的观察者。
Temperature Observer: Temperature is now 25, Humidity is 60
Humidity Observer: Temperature is now 25, Humidity is 60
Temperature Observer: Temperature is now 23, Humidity is 65
Humidity Observer: Temperature is now 23, Humidity is 65
Humidity Observer: Temperature is now 22, Humidity is 70
3.4.结果分析
- 当气象站的数据首次更新为温度25度、湿度60%时,两个观察者都收到了通知。
- 再次更新数据为温度23度、湿度65%时,同样的两个观察者都收到了通知。
- 当
temperatureObserver
被移除后,仅剩humidityObserver
接收到了气象站数据的更新通知(温度22度、湿度70%)。
这说明观察者模式在C语言中得到了正确的实现。每当气象站的数据发生变化时,所有注册的观察者都会接收到通知并执行相应的更新操作。如果某个观察者不再需要接收更新,可以将其从气象站中移除,从而避免不必要的通知。