13 patrón de diseño _ patrón de observador _ implementación del lenguaje C

Modo observador

1 escena de simulación

Supongamos que queremos desarrollar un altavoz inteligente. Hay muchos servicios en altavoces inteligentes, como: "servicio de pronóstico del tiempo", "servicio de programación", etc.

Todos estos servicios deben estar conectados al servidor en la nube, lo que significa que todos deben usar la dirección IP del altavoz inteligente. La dirección IP de los altavoces inteligentes se gestiona mediante un "servicio de gestión de IP" especial. Esto plantea una pregunta: cuando el usuario modifica la dirección IP del altavoz inteligente a través del "servicio de gestión de IP", ¿cómo saben el "servicio de pronóstico del tiempo" y el "servicio de programación" que la dirección IP ha cambiado?

Hay dos formas de resolver este problema:

La primera forma:

Desde "servicio de pronóstico del tiempo", "servicio de programación" hasta "servicio de gestión de IP" para consultar si la dirección IP ha cambiado.

El problema con este enfoque es: ¿Cuándo deberían el "servicio de pronóstico del tiempo" y el "servicio de programación" buscar direcciones IP? La frecuencia de consulta es baja y la dirección IP no se actualiza a tiempo, lo que puede provocar fallas comerciales. Pero no puede verificarlo una vez sin enviar un paquete, ¿verdad?

Por tanto, este camino básicamente no funciona.

Mira la segunda forma:

El "servicio de administración de IP" informa proactivamente al "servicio de pronóstico del tiempo" y al "servicio de programación" de la nueva dirección IP cuando la dirección IP cambia.

Este método resuelve el problema anterior, pero ¿cómo sabe el "servicio de gestión de IP" qué servicios notificar? Suponiendo que ahora se agrega un nuevo servicio que requiere una dirección IP, ¿es necesario modificar el "servicio de administración de IP"?

Además, la interfaz a través de la cual cada servicio recibe una dirección IP también puede ser diferente ¿Implementa el "servicio de gestión de IP" una interfaz para cada servicio?

El modo de observador puede resolver todos los problemas mencionados anteriormente.

Veamos cómo el modelo del observador resuelve estos problemas.

2 Introducción al modo de observador

La realización del modo observador se divide principalmente en dos enlaces: "registro" y "notificación":

Para registro":

El "Servicio de gestión de IP" proporciona una interfaz para registrar y eliminar servicios de observador. El "Servicio meteorológico", el "Servicio de programación" y otros servicios que requieren el uso de direcciones IP se registran con el "Servicio de administración de IP" según una interfaz unificada. Establecer la relación de dependencia entre "servicio de gestión de IP" y "servicio de pronóstico del tiempo", "servicio de programación" y otros servicios mediante el registro.

Esto resuelve el problema de cómo el "servicio de gestión de IP" sabe qué servicios notificar .

Al registrarse, el "servicio de pronóstico del tiempo", el "servicio de programación" y otros servicios proporcionan una función de devolución de llamada para informar al "servicio de gestión de IP" de la nueva dirección IP. La función de devolución de llamada se implementa de acuerdo con una interfaz unificada definida.

Este es el problema de que la interfaz de cada servicio que recibe la dirección IP puede ser diferente .

Si agrega un nuevo servicio que requiere el uso de una dirección IP, puede registrarse con el "Servicio de administración de IP" para proporcionar una interfaz de registro en cualquier momento. No hay impacto en la interfaz y la implementación del "Servicio de administración de IP".

Esto resuelve el problema de modificar el "servicio de gestión de IP" al agregar un nuevo servicio que requiere una dirección IP .

Para "notificaciones":

El "servicio de gestión de IP" solo llama a la función de devolución de llamada proporcionada durante el registro de servicios tales como "servicio de pronóstico del tiempo" y "servicio de programación" cuando la dirección IP cambia para informar la nueva dirección IP.

Esto resuelve el problema de que el "servicio de pronóstico del tiempo" y el "servicio de programación" no saben cuándo consultar la dirección IP .

Debido a los dos enlaces de "registro" y "notificación", el modelo de observador también se denomina "modelo de publicación-suscripción". "Publicar" corresponde a "Notificación" y "Suscripción" corresponde a "Registro".

3 Implementación detallada utilizando el patrón de observador

Partícipe

  1. Asunto: IpSubject

Objetivo de observación abstracto, que proporciona una interfaz para registrar y eliminar observadores

  1. ConcreteSubject: IpMngService

El objetivo de observación específico es el "servicio de gestión de IP" en el ejemplo anterior

  1. Observador: IpObserver

El observador abstracto define la interfaz de la función de devolución de llamada para el "servicio de gestión de IP" para informar la dirección IP.

  1. ConcreteObserver: WeatherReportService, ScheduleService

Observadores específicos, implementan la función de devolución de llamada que informa la dirección IP

UML

Inserte la descripción de la imagen aquí

Código de muestra de 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;
}

Código de muestra de 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;
}

Código de muestra de IpObserver

ip_observer.h

#ifndef IP_OBSERVER_H
#define IP_OBSERVER_H

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

Código de muestra de 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;
}

Código de muestra de 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;
}

Ejemplo de código de cliente

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

Ejemplo de visualización del cliente

-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

Supongo que te gusta

Origin blog.csdn.net/weixin_46826913/article/details/107896785
Recomendado
Clasificación