13设计模式_观察者模式_C语言实现

观察者模式

1 模拟场景

假设我们要开发一个智能音箱。智能音箱上有很多服务,比如:“天气预报服务”、“日程安排服务”,等等。

这些服务都需要和云端服务器连接,也就是说都需要使用智能音箱的IP地址。而智能音箱的IP地址是有专门的“IP管理服务”管理的。这就产生了一个问题:当用户通过“IP管理服务”修改了智能音箱的IP地址后,“天气预报服务”、“日程安排服务”怎么知道IP地址变化了呢?

解决这个问题无非两条路:

第一条路:

由“天气预报服务”、“日程安排服务”向“IP管理服务”查询IP地址有没有变化。

这种做法的问题是:“天气预报服务”、“日程安排服务”该在什么时候查询IP地址呢?查询频率低了,IP地址更新不及时,可能导致业务失败。但也不能没发一个包就查询一次吧?

所以,这条路基本行不通。

再看第二条路:

“IP管理服务”在IP地址变化时主动将新的IP地址告知给“天气预报服务”、“日程安排服务”。

这个方法解决了前面的问题,但 “IP管理服务”怎么知道要告知给哪些服务呢?假设现在又新增一个需要使用IP地址的服务,难道需要修改“IP管理服务”?

另外,每个服务接收IP地址的接口也可能不同,难道“IP管理服务”要为每个服务实现一条接口?

观察者模式可以解决上面提到的所有问题。

我们来看下观察者模式是怎么解决这些问题的。

2 观察者模式简介

观察者模式的实现主要分为“注册”和“通知”两个环节:

对于“注册”:

“IP管理服务”提供注册和删除观察者服务的接口。“天气预报服务”、“日程安排服务”及其它需要使用IP地址的服务都按统一的接口向“IP管理服务”进行注册。通过注册建立起“IP管理服务”和“天气预报服务”、“日程安排服务”等服务之间的依赖关系。

这就解决了“IP管理服务”怎么知道要告知给哪些服务的问题

注册时,“天气预报服务”、“日程安排服务”等服务提供一个告知新的IP地址的回调函数给“IP管理服务”。该回调函数按定义好的统一的接口实现。

这就每个服务接收IP地址的接口可能不同的问题

如果新增一个需要使用IP地址的服务,随时都可以“IP管理服务”提供注册接口进行注册。对“IP管理服务”的接口和实现都没有任何影响。

这就解决了新增一个需要使用IP地址的服务需要修改“IP管理服务”的问题

对于“通知”:

“IP管理服务”仅在IP地址变化时调用“天气预报服务”、“日程安排服务”等服务注册时提供的回调函数告知新的IP地址。

这就解决了“天气预报服务”、“日程安排服务”不知道该在什么时候查询IP地址的问题

因为“注册”和“通知”两个环节,所以观察者模式也被称作“发布-订阅模式”。“发布”对应“通知”,“订阅”对应“注册”。

3 使用观察者模式的详细实现

参与者

  1. Subject: IpSubject

抽象观察目标,提供注册和删除观察者的接口

  1. ConcreteSubject: IpMngService

具体观察目标,也就是上述例子中的“IP管理服务”

  1. Observer: IpObserver

抽象观察者,定义“IP管理服务”告知IP地址的回调函数接口。

  1. ConcreteObserver: WeatherReportService, ScheduleService

具体观察者,实现告知IP地址的回调函数

UML

在这里插入图片描述

IpSubject示例代码

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示例代码

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示例代码

ip_observer.h

#ifndef IP_OBSERVER_H
#define IP_OBSERVER_H

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

WeatherReportService示例代码

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示例代码

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;
}

客户端代码示例

#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");
}

客户端显示示例

-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

猜你喜欢

转载自blog.csdn.net/weixin_46826913/article/details/107896785
今日推荐