12 patrón de diseño _ patrón de visitante _ implementación del lenguaje C

Modo visitante

1 escena de simulación

Supongamos que queremos desarrollar un controlador de puerto de red. Hay dos tipos de puertos de red: puertos de red de baja velocidad y puertos de red de alta velocidad. Cada tipo de puerto de red admite el funcionamiento de la velocidad de configuración y el modo de configuración. Entonces nuestro controlador se ve así:

Inserte la descripción de la imagen aquí

Suponiendo que se haya implementado el procedimiento anterior, ahora debido a necesidades comerciales, necesitamos agregar la operación de tasa de consulta.

Luego, necesitamos modificar la clase Mac implementada y sus subclases, y agregar GetSpeed ​​() a la clase Mac y sus subclases. El controlador modificado es el siguiente:

Inserte la descripción de la imagen aquí

Esta modificación obviamente viola el "principio de apertura y cierre".

¿Hay alguna forma de agregar GetSpeed ​​() a la clase Mac y sus subclases sin modificarlas?

El modelo de visitante proporciona tal método.

Por supuesto, debe haber un requisito previo para usar el modo de visitante, es decir, al diseñar la clase Mac, debemos anticipar la posibilidad de agregar operaciones a la clase Mac en el futuro y reservar una interfaz común para agregar operaciones dinámicamente en tiempo de ejecución.

Comencemos con el patrón de visitantes desde el principio.

2 Introducción al modo visitante

La intención del patrón de visitante dado por GoF es: representar una operación que actúa sobre cada elemento en una estructura de objeto. Es que puedes definir nuevas operaciones que actúen sobre estos elementos sin cambiar la clase de cada elemento.

Específico para el escenario anterior: cada elemento es la clase Mac y sus subclases. La nueva operación es GetSpeed ​​().

Definimos la nueva operación como Visitor y agregamos una subclase de Visitor cada vez que se agrega una nueva operación.

Cuando definimos la clase Mac, necesitamos reservar una interfaz general Accept (Visitor) para agregar operaciones dinámicamente en tiempo de ejecución. Aceptar puede recibir nuevas operaciones. De esta manera, no importa cuántas operaciones nuevas se agreguen más tarde, las nuevas operaciones se pueden aplicar a la Mac a través de Aceptar.

Veamos la implementación específica del patrón de visitantes.

3 Utilice el modo de visitante para implementar el controlador de puerto de red

Partícipe

  1. Visitante

Declare a qué elementos puede acceder el visitante y declare una operación de visitante para cada elemento al que se puede acceder.

En el escenario anterior, hay dos elementos accesibles: HighSpeedMac y LowSpeedMac. Por lo tanto, es necesario declarar las operaciones de visitante VisitLowSpeedMac () y VisitHignSpeedMac () para HighSpeedMac y LowSpeedMac respectivamente.

  1. ConcreteVisitor: GetSpeedVisitor

Implementar las operaciones declaradas por el Visitante. Cada vez que se agrega una operación, es necesario agregar un ConcreteVisitor.

Tomemos la adición de GetSpeed ​​() como ejemplo. Si necesitamos agregar GetMode () más tarde, solo necesitamos definir GetModeVisitor nuevamente.

  1. Elemento: Mac

Necesita reservar una interfaz general Aceptar para agregar operaciones dinámicamente en tiempo de ejecución

  1. ConcreteElement: LowSpeedMac 、 HighSpeedMac

Darse cuenta del método y aceptar ConcreteElement en sí.

  1. ObjectStruct

Proporcione una interfaz para enumerar Element. En este ejemplo, solo definiremos dos Elementos como ejemplos, por lo que enumeraremos los Elementos directamente en la función principal, sin definir un ObjectStruct especial.

UML

Inserte la descripción de la imagen aquí

Código de muestra de visitante

visitante.h

#ifndef VISITOR_H
#define VISITOR_H

#include "mac.h"

struct Visitor {
    void (*VisitLowSpeedMac)(struct Visitor *this, struct Mac *lowSpeedMac);
    void (*VisitHighSpeedMac)(struct Visitor *this, struct Mac *highSpeedMac);
};

#endif

Código de muestra de GetSpeedVisitor

get_speed_visitor.h

#ifndef GET_SPEED_VISITOR_H
#define GET_SPEED_VISITOR_H

#include "visitor.h"

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

// 析构函数
void _GetSpeedVisitor(struct Visitor *this);

#endif

get_speed_visitor.c

#include "get_speed_visitor.h"
#include <stddef.h>
#include <stdio.h>

static void VisitLowSpeedMac(struct Visitor *this, struct Mac *lowSpeedMac)
{
    printf("  get speed for low speed mac, speed is \"%s\"\n", lowSpeedMac->speed);
}

static void VisitHighSpeedMac(struct Visitor *this, struct Mac *highSpeedMac)
{
    printf("  get speed for high speed mac, speed is \"%s\"\n", highSpeedMac->speed);
}

// 构造函数
void GetSpeedVisitor(struct Visitor *this)
{
    this->VisitLowSpeedMac = VisitLowSpeedMac;
    this->VisitHighSpeedMac = VisitHighSpeedMac;
}

// 析构函数
void _GetSpeedVisitor(struct Visitor *this)
{
    this->VisitLowSpeedMac = NULL;
    this->VisitHighSpeedMac = NULL;
}

Código de muestra de Mac

mac.h

#ifndef MAC_H
#define MAC_H

#include "visitor.h"

struct Mac {
    char mode[50];
    char speed[50];
    // 编译时已实现的操作
    void (*SetMode)(struct Mac *this, char *mode);
    void (*SetSpeed)(struct Mac *this, char *speed);
    // 用于在运行时扩展操作
    void (*Accept)(struct Mac *this, struct Visitor *visitor);
};

#endif

Código de muestra LowSpeedMac

low_speed_mac.h

#ifndef LOW_SPEED_MAC_H
#define LOW_SPEED_MAC_H

#include "mac.h"

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

// 析构函数
void _LowSpeedMac(struct Mac *this);

#endif

low_speed_mac.c

#include "low_speed_mac.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h> 

static void SetMode(struct Mac *this, char *mode)
{
    strcpy(this->mode, mode);
    printf("  set mode for low speed mac, mode is \"%s\"\n", mode);
}

static void SetSpeed(struct Mac *this, char *speed)
{
    strcpy(this->speed, speed);
    printf("  set speed for low speed mac, speed is \"%s\"\n", speed);
}

static void Accept(struct Mac *this, struct Visitor *visitor)
{
    visitor->VisitLowSpeedMac(visitor, this);
}

// 构造函数
void LowSpeedMac(struct Mac *this)
{
    this->mode[0] = 0;
    this->speed[0] = 0;
    this->SetMode = SetMode;
    this->SetSpeed = SetSpeed;
    this->Accept = Accept;
}

// 析构函数
void _LowSpeedMac(struct Mac *this)
{
    this->mode[0] = 0;
    this->speed[0] = 0;
    this->SetMode = NULL;
    this->SetSpeed = NULL;
    this->Accept = NULL;
}

Código de muestra de HighSpeedMac

high_speed_mac.h

#ifndef HIGH_SPEED_MAC_H
#define HIGH_SPEED_MAC_H

#include "mac.h"

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

// 析构函数
void _HighSpeedMac(struct Mac *this);

#endif

high_speed_mac.c

#include "high_speed_mac.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h> 

static void SetMode(struct Mac *this, char *mode)
{
    strcpy(this->mode, mode);
    printf("  set mode for high speed mac, mode is \"%s\"\n", mode);
}

static void SetSpeed(struct Mac *this, char *speed)
{
    strcpy(this->speed, speed);
    printf("  set speed for high speed mac, speed is \"%s\"\n", speed);
}

static void Accept(struct Mac *this, struct Visitor *visitor)
{
    visitor->VisitHighSpeedMac(visitor, this);
}

// 构造函数
void HighSpeedMac(struct Mac *this)
{
    this->mode[0] = 0;
    this->speed[0] = 0;
    this->SetMode = SetMode;
    this->SetSpeed = SetSpeed;
    this->Accept = Accept;
}

// 析构函数
void _HighSpeedMac(struct Mac *this)
{
    this->mode[0] = 0;
    this->speed[0] = 0;
    this->SetMode = NULL;
    this->SetSpeed = NULL;
    this->Accept = NULL;
}

Ejemplo de código de cliente

#include "low_speed_mac.h"
#include "high_speed_mac.h"
#include "get_speed_visitor.h"
#include <stdio.h>

void main()
{
    struct Mac lowSpeedMac;
    LowSpeedMac(&lowSpeedMac);
    struct Mac highSpeedMac;
    HighSpeedMac(&highSpeedMac);

    printf("调用低速网口编译时已实现的操作:\n");
    lowSpeedMac.SetSpeed(&lowSpeedMac, "1G");
    lowSpeedMac.SetMode(&lowSpeedMac, "GMII");
    printf("\n");
    printf("调用高速网口编译时已实现的操作:\n");
    highSpeedMac.SetSpeed(&highSpeedMac, "50G");
    highSpeedMac.SetMode(&highSpeedMac, "SGMII");
    printf("\n");
   
    printf("--扩展getSpeed操作--\n");
    printf("\n");
    struct Visitor getSpeedVisitor;
    GetSpeedVisitor(&getSpeedVisitor);
    printf("调用低速网口运行时扩展的操作:\n");
    lowSpeedMac.Accept(&lowSpeedMac, &getSpeedVisitor);
    printf("\n");
    printf("调用高速网口运行时扩展的操作:\n");
    highSpeedMac.Accept(&highSpeedMac, &getSpeedVisitor);
    printf("\n");
}

Ejemplo de visualización del cliente

-bash-4.2# ./test
调用低速网口编译时已实现的操作:
  set speed for low speed mac, speed is "1G"
  set mode for low speed mac, mode is "GMII"

调用高速网口编译时已实现的操作:
  set speed for high speed mac, speed is "50G"
  set mode for high speed mac, mode is "SGMII"

--扩展getSpeed操作--

调用低速网口运行时扩展的操作:
  get speed for low speed mac, speed is "1G"

调用高速网口运行时扩展的操作:
  get speed for high speed mac, speed is "50G"

4 Restricciones sobre el uso del modo visitante

Limite uno:

Hemos mencionado una de las limitaciones en la descripción anterior: al diseñar el Elemento, anticipamos que las operaciones podrían agregarse al Elemento en el futuro, y reservamos una interfaz común para agregar operaciones dinámicamente en tiempo de ejecución, a saber: Aceptar ().

Límite dos:

También hay una restricción más estricta: cuántas subclases de Element deben ser estables.

Porque en el Visitante necesita declarar una operación de Visitante para cada elemento (es decir, cada subclase de Elemento). Por lo tanto, al agregar una subclase de Elemento, debe modificar la definición de Visitante para agregar una nueva operación de Visitante. Obviamente, esto viola el "principio de apertura y cierre".

Por lo tanto, tenga en cuenta: el escenario en este artículo en realidad asume que Mac tiene solo dos subcategorías, LowSpeedMac y HighSpeedMac. Esta es una restricción más estricta. En realidad, la subcategoría de Mac no es estable, porque es muy probable que sea necesario agregar SuperHighSpeedMac en el futuro. En este caso, el modelo de visitante no es aplicable.

Supongo que te gusta

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