Application Example of the Observer Pattern in C Language Projects
The Observer Pattern is a behavioral design pattern that defines a one-to-many dependency between objects, so that when one object (the subject) changes state, all its dependents (the observers) are notified and updated automatically. This pattern is widely used in event handling systems, GUI frameworks, and other scenarios.
This tutorial will demonstrate how to implement the Observer Pattern through a simple C language example.
Pattern Overview
In our example, we will create a simple weather station as the subject, and when the weather data changes, all registered display devices (observers) will automatically receive the latest data.
Role Breakdown
- Subject: The object being observed, such as
<span>WeatherData</span>. This role can add, remove, and notify observers. - Observer: The object that receives update notifications, such as
<span>CurrentConditionsDisplay</span>and<span>StatisticsDisplay</span>. - Concrete Subject and Concrete Observer: Classes that implement the interface and provide specific functionality.
Example Code
#include <stdio.h>
#include <stdlib.h>
typedef struct Observer { void (*update)(struct Observer*, float);} Observer;
typedef struct Subject { Observer** observers; int observer_count;
void (*attach)(struct Subject*, Observer*); void (*detach)(struct Subject*, Observer*); void (*notify)(struct Subject*, float);} Subject;
// The observed weather data
typedef struct WeatherData { Subject subject; // Embed Subject into WeatherData float temperature;} WeatherData;
// Update weather data and notify all observers
void weather_data_notify(Subject* this, float temperature) { for (int i = 0; i < this->observer_count; ++i) { this->observers[i]->update(this->observers[i], temperature); }}
// Add a new observer
void weather_data_attach(Subject* this, Observer* obs) { if (this->observer_count < 10) { // Maximum of 10 observers this->observers[this->observer_count++] = obs; printf("Attached an observer.\n"); } else { printf("Max observer count reached!\n"); }}
// Remove an observer
void weather_data_detach(Subject* this, Observer* obs) { for (int i = 0; i < this->observer_count; ++i) { if (this->observers[i] == obs){ for(int j = i; j < this->observer_count - 1; j++) this->observers[j] = this->observers[j + 1]; --this->observer_count; printf("Detached an observer.\n"); return; } }}
void weather_data_set_measurements(WeatherData* wd, float temperature){ wd ->temperature = temperature; wd ->subject.notify(&wd -> subject, wd ->temperature); }
// Current conditions display
typedef struct CurrentConditionsDisplay { Observer base; // Embed Observer into Current Conditions Display
} CurrentConditionsDisplay;
// Update method implementation, print current temperature information void current_conditions_display_update(Observer *obs, float temp){ printf("Current conditions: %f degree Celsius\n", temp);}
int main() {
WeatherData weatherData;
// Initialize weather data related information and function pointers. weatherData.subject.observer_count = 0; weatherData.subject.observers=(Observer**)malloc(sizeof(Observer*) *10);
weatherData.subject.attach=&weather_data_attach;// Call attach method to add observer weatherData.subject.detach=&weather_data_detach;// Used to detach observer
CurrentConditionsDisplay curCondDisp ;// Separate structure for current conditions
curCondDisp.base.update=current_conditions_display_update;// Assign update method to base data
}