13 design pattern _ observer pattern _ C language implementation

Observer mode

1 Simulation scene

Suppose we want to develop a smart speaker. There are many services on smart speakers, such as: "weather forecast service", "schedule service", and so on.

These services all need to be connected to the cloud server, which means that they all need to use the IP address of the smart speaker. The IP address of smart speakers is managed by a special "IP management service". This raises a question: when the user modifies the IP address of the smart speaker through the "IP management service", how do the "weather forecast service" and "schedule service" know that the IP address has changed?

There are two ways to solve this problem:

The first way:

From "weather forecast service", "schedule service" to "IP management service" to inquire whether the IP address has changed.

The problem with this approach is: When should the "weather forecast service" and "schedule service" look up IP addresses? The query frequency is low, and the IP address is not updated in time, which may cause business failure. But you can't check it once without sending a package, right?

Therefore, this road basically does not work.

Look at the second way:

"IP management service" proactively informs "weather forecast service" and "schedule service" of the new IP address when the IP address changes.

This method solves the previous problem, but how does the "IP management service" know which services to notify? Assuming that a new service that requires an IP address is added now, does it need to modify the "IP management service"?

In addition, the interface through which each service receives an IP address may also be different. Does the "IP management service" implement an interface for each service?

The observer mode can solve all the problems mentioned above.

Let's see how the observer model solves these problems.

2 Introduction to Observer Mode

The realization of the observer mode is mainly divided into two links: "registration" and "notification":

For "registration":

"IP Management Service" provides an interface for registering and deleting observer services. "Weather Service", "Schedule Service" and other services that require the use of IP addresses are registered with "IP Management Service" according to a unified interface. Establish the dependency relationship between "IP management service" and "weather forecast service", "schedule service" and other services through registration.

This solves the problem of how the "IP management service" knows which services to notify .

When registering, the "weather forecast service", "schedule service" and other services provide a callback function to inform the "IP management service" of the new IP address. The callback function is implemented according to a defined unified interface.

This is the problem that the interface of each service receiving IP address may be different .

If you add a new service that requires the use of an IP address, you can register with the "IP Management Service" to provide a registration interface at any time. There is no impact on the interface and implementation of the "IP Management Service".

This solves the problem of modifying the "IP management service" when adding a new service that requires an IP address .

For "notifications":

"IP management service" only calls the callback function provided during registration of services such as "weather forecast service" and "schedule service" when the IP address changes to inform the new IP address.

This solves the problem that "weather forecast service" and "schedule service" don't know when to query the IP address .

Because of the two links of "registration" and "notification", the observer model is also called the "publish-subscribe model". "Publishing" corresponds to "Notification", and "Subscription" corresponds to "Registration".

3 Detailed implementation using the observer pattern

Participant

  1. Subject: IpSubject

Abstract observation target, providing an interface for registering and deleting observers

  1. ConcreteSubject: IpMngService

The specific observation target is the "IP management service" in the above example

  1. Observer: IpObserver

The abstract observer defines the callback function interface for the "IP management service" to inform the IP address.

  1. ConcreteObserver: WeatherReportService, ScheduleService

Specific observers, implement the callback function that informs the IP address

UML

Insert picture description here

IpSubject sample code

ip_subject.h

#ifndef IP_SUBJECT_H
#define IP_SUBJECT_H

#include "ip_observer.h"

struct IpSubject {
    struct IpObserver *ipObserverList[50];
    void (*Attach)(struct IpSubject *this, struct IpObserver *ipObserver);
    void (*Detach)(struct IpSubject *this, struct IpObserver *ipObserver);
    void (*Notify)(struct IpSubject *this, char *ip);
};

// 构造函数
void IpSubject(struct IpSubject *this);

// 析构函数
void _IpSubject(struct IpSubject *this);

#endif

ip_subject.c

#include "ip_subject.h"
#include <stdio.h>

static void Attach(struct IpSubject *this, struct IpObserver *ipObserver)
{
    int i;    
    for (i = 0; i < sizeof(this->ipObserverList) / sizeof(struct IpObserver *); i++) {
        if (this->ipObserverList[i] == NULL) {
            this->ipObserverList[i] = ipObserver;
            return;
        }
    }
    printf("err: list full\n");
}

static void Detach(struct IpSubject *this, struct IpObserver *ipObserver)
{
    int i;    
    for (i = 0; i < sizeof(this->ipObserverList) / sizeof(struct IpObserver *); i++) {
        if (this->ipObserverList[i] == ipObserver) {
            this->ipObserverList[i] = NULL;
        }
    }
}

static void Notify(struct IpSubject *this, char *ip)
{
    int i;    
    for (i = 0; i < sizeof(this->ipObserverList) / sizeof(struct IpObserver *); i++) {
        if (this->ipObserverList[i] != NULL) {
            this->ipObserverList[i]->UpdateIp(this->ipObserverList[i], ip);
        }
    }
}

// 构造函数
void IpSubject(struct IpSubject *this)
{
    int i;    
    for (i = 0; i < sizeof(this->ipObserverList) / sizeof(struct IpObserver *); i++) {
        this->ipObserverList[i] = NULL;
    }
    this->Attach = Attach;
    this->Detach = Detach;
    this->Notify = Notify;
}

// 析构函数
void _IpSubject(struct IpSubject *this)
{
    int i;    
    for (i = 0; i < sizeof(this->ipObserverList) / sizeof(struct IpObserver *); i++) {
        this->ipObserverList[i] = NULL;
    }
    this->Attach = NULL;
    this->Detach = NULL;
    this->Notify = NULL;
}

IpMngService sample code

ip_mng_service.h

#ifndef IP_MNG_SERVICE_H
#define IP_MNG_SERVICE_H

#include "ip_subject.h"

struct IpMngService {
    struct IpSubject parent;
    char ip[20];
    void (*SetIp)(struct IpMngService *this, char * ip);
    void (*GetIp)(struct IpMngService *this, char *ip);
};

// 构造函数
void IpMngService(struct IpMngService *this);

// 析构函数
void _IpMngService(struct IpMngService *this);

#endif

ip_mng_service.c

#include "ip_mng_service.h"
#include <string.h>
#include <stdio.h>

static void SetIp(struct IpMngService *this, char *ip)
{
    strcpy(this->ip, ip);
    printf("  IP地址修改为:%s\n", this->ip);
    this->parent.Notify(&(this->parent), ip);
}

static void GetIp(struct IpMngService *this, char *ip)
{
    strcpy(ip, this->ip);
}

// 构造函数
void IpMngService(struct IpMngService *this)
{
    IpSubject(&(this->parent));
    memset(this->ip, 0, sizeof(this->ip));
    this->SetIp = SetIp;
    this->GetIp = GetIp;
}

// 析构函数
void _IpMngService(struct IpMngService *this)
{
    _IpSubject(&(this->parent));
    memset(this->ip, 0, sizeof(this->ip));
    this->SetIp = NULL;
    this->GetIp = NULL;
}

IpObserver sample code

ip_observer.h

#ifndef IP_OBSERVER_H
#define IP_OBSERVER_H

struct IpObserver {
    void (*UpdateIp)(struct IpObserver *this, char *ip);
};
#endif

WeatherReportService sample code

weather_report_service.h

#ifndef WEATHER_REPORT_SERVICE_H
#define WEATHER_REPORT_SERVICE_H

#include "ip_observer.h"

struct WeatherReportService {
    struct IpObserver parent;
    char ip[20];
};

// 构造函数
void WeatherReportService(struct WeatherReportService *this);

// 析构函数
void _WeatherReportService(struct WeatherReportService *this);

#endif

weather_report_service.c

#include "weather_report_service.h"
#include <stdio.h>
#include <string.h>

static void UpdateIp(struct WeatherReportService *this, char *ip)
{
    strcpy(this->ip, ip);
    printf("  “天气预报服务”的IP地址已更新为:%s\n", this->ip);
}

// 构造函数
void WeatherReportService(struct WeatherReportService *this)
{
    memset(this->ip, 0, sizeof(this->ip));
    this->parent.UpdateIp = (void(*)(struct IpObserver*, char*))UpdateIp;
}

// 析构函数
void _WeatherReportService(struct WeatherReportService *this)
{
    memset(this->ip, 0, sizeof(this->ip));
    this->parent.UpdateIp = NULL;
}

ScheduleService sample code

schedule_service.h

#ifndef SCHEDULE_SERVICE_H
#define SCHEDULE_SERVICE_H

#include "ip_observer.h"

struct ScheduleService {
    struct IpObserver parent;
    char ip[20];
};

// 构造函数
void ScheduleService(struct ScheduleService *this);

// 析构函数
void _ScheduleService(struct ScheduleService *this);

#endif

schedule_service.c

#include "schedule_service.h"
#include <stdio.h>
#include <string.h>

static void UpdateIp(struct ScheduleService *this, char *ip)
{
    strcpy(this->ip, ip);
    printf("  “日程管理服务”的IP地址已更新为:%s\n", this->ip);
}

// 构造函数
void ScheduleService(struct ScheduleService *this)
{
    memset(this->ip, 0, sizeof(this->ip));
    this->parent.UpdateIp = (void(*)(struct IpObserver*, char*))UpdateIp;
}

// 析构函数
void _ScheduleService(struct ScheduleService *this)
{
    memset(this->ip, 0, sizeof(this->ip));
    this->parent.UpdateIp = NULL;
}

Client code example

#include "ip_mng_service.h"
#include "weather_report_service.h"
#include "schedule_service.h"
#include <stdio.h>

void main()
{
    struct IpMngService ipMngService;
    IpMngService(&ipMngService);

    struct WeatherReportService weatherReportService;
    WeatherReportService(&weatherReportService);

    struct ScheduleService scheduleServiec;
    ScheduleService(&scheduleServiec);

    printf("仅将“天气预报服务”注册为观察者,效果如下:\n");
    ipMngService.parent.Attach(&(ipMngService.parent), (struct IpObserver*)&weatherReportService);
    ipMngService.SetIp(&ipMngService, "10.78.100.111");
    printf("\n");

    printf("再将“日程管理服务”也注册为观察者,效果如下:\n");
    ipMngService.parent.Attach(&(ipMngService.parent), (struct IpObserver*)&scheduleServiec);
    ipMngService.SetIp(&ipMngService, "10.78.100.222");
}

Client display example

-bash-4.2# ./test
仅将“天气预报服务”注册为观察者,效果如下:
  IP地址修改为:10.78.100.111
  “天气预报服务”的IP地址已更新为:10.78.100.111

再将“日程管理服务”也注册为观察者,效果如下:
  IP地址修改为:10.78.100.222
  “天气预报服务”的IP地址已更新为:10.78.100.222
  “日程管理服务”的IP地址已更新为:10.78.100.222

Guess you like

Origin blog.csdn.net/weixin_46826913/article/details/107896785