14 patrón de diseño _ patrón de método de plantilla _ implementación del lenguaje C

Patrón de método de plantilla

1 escena de simulación

Supongamos que somos un proveedor de chips y ahora hemos desarrollado una nueva CPU. Varios controladores de bus están integrados en la CPU, como i2c, spi, usb, etc. Para permitir que los clientes utilicen nuestra CPU sin problemas, debemos proporcionarles un software de controlador compatible con varios controladores de bus.

Tomemos i2c como ejemplo para ver cómo es el software de controlador que ofrecemos a los clientes como proveedores de chips.

(PD: asumo que el lector tiene cierta comprensión del software del controlador, por lo que los conceptos básicos de i2c y el software del controlador no se explicarán en este artículo)

Suponemos que el pseudocódigo impulsado por la "operación de lectura i2c" es el siguiente:

I2cRead()
{
    if (I2cAdaptorOperation()) {  // 第一步
        I2cClientOperation()  // 第二步
    }    
}

I2cAdaptorOperation()
{
    具体实现略   
}

I2cClientOperation()
{
    具体实现略
}

Lo anterior es el pseudocódigo para toda la unidad de "operación de lectura i2c". El pseudocódigo anterior se divide en tres partes:

La primera parte es I2cAdaptorOperation (). Es el funcionamiento del controlador i2c integrado en la CPU. La implementación de esta parte del código es nuestra responsabilidad (es decir, el proveedor del chip). Debido a que nosotros implementamos el controlador i2c, sabemos cómo implementar el controlador del controlador i2c.

La segunda parte es I2cClientOperation (). Es el funcionamiento de los periféricos i2c. La implementación de esta parte del código es responsabilidad del cliente. Debido a que los clientes pueden usar nuestra CPU para conectar varios periféricos i2c (como el rtc de i2c, el led de i2c), no sabemos cuáles son los periféricos del cliente, por lo que no hay forma de implementar esta parte del código.

La tercera parte es I2cRead (). Es el código de flujo principal de la operación de lectura de i2c. Entonces, ¿esta parte del código es implementada por nosotros o por el cliente? Ambos métodos son comunes.

Por la forma en que el cliente es responsable de implementar I2cRead (): En general, nosotros (es decir, el proveedor de chips) hemos definido claramente cómo se debe implementar I2cRead () al diseñar el controlador i2c, y los clientes a menudo no saben cómo implementar I2cRead (). Por lo tanto, generalmente proporcionamos a los clientes el código DEMO de I2cRead () como referencia, y el cliente implementará I2cRead () de acuerdo con el código DEMO.

Por la forma en que nosotros (es decir, el proveedor de chips) es responsable de implementar I2cRead (): I2cRead () necesita llamar a I2cClientOperation (), y I2cClientOperation () es implementado por el cliente. Entonces, cuando implementamos I2cRead (), I2cClientOperation () aún no se ha implementado. En este momento, solo podemos definir la interfaz abstracta de I2cClientOperation () y llamar a la interfaz abstracta de I2cClientOperation () en I2cRead (), y luego el cliente reescribe la interfaz abstracta de I2cClientOperation ().

Aquí "la forma en que nosotros (es decir, el proveedor de chips) es responsable de implementar I2cRead ()" es el método de plantilla. Tomemos esto como ejemplo para aclarar la idea y la implementación del método de plantilla.

2 Introducción al método de plantilla

El método de plantilla define el esqueleto del algoritmo de una operación y retrasa algunos pasos a las subclases. El método de plantilla permite que las subclases redefinan ciertos pasos específicos de un algoritmo sin cambiar la estructura del algoritmo.

Corresponde al ejemplo anterior:

I2cRead () es el esqueleto del algoritmo

I2cClientOperation () es el paso de retrasar a la subclase

3 Utilice el método de plantilla para realizar el controlador de "operación de lectura i2c" para el proveedor del chip

Partícipe

  1. AbstractClass: I2cRead

El flujo principal de la operación de lectura de i2c contiene la implementación de los métodos llamados en el flujo. Pero el método I2cClientOperation () debe ser reescrito por una clase específica.

Esta parte la implementa el proveedor de chips de CPU que integra el controlador i2c.

  1. ConcreteClass: RtcI2cRead 、 LedI2cRead

Heredar I2cRead y reescribir I2cClientOperation () de acuerdo con las condiciones específicas de los periféricos (rtc, led).

Esta parte es complicada por los clientes que compran chips de CPU.

UML

Inserte la descripción de la imagen aquí

I2cRead código de muestra

i2c_read.h

#ifndef I2C_READ_H
#define I2C_READ_H

struct I2cRead {
    void (*Read)(struct I2cRead *this, char *operationCode, char *ret);
    int (*AdapterOperation)(struct I2cRead *this);
    void (*ClientOperation)(struct I2cRead *this, char *operationCode, char *ret);
};

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

// 析构函数
void _I2cRead(struct I2cRead *this);

#endif

i2c_read.c

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

static void Read(struct I2cRead *this, char *operationCode, char *ret)
{
    if (this->AdapterOperation(this) == 0) {
        this->ClientOperation(this, operationCode, ret);
    }    
}

static int AdapterOperation(struct I2cRead *this)
{
    printf("  执行i2c适配器操作\n");
    return 0;
}

static void ClientOperation(struct I2cRead *this, char *operationCode, char *ret)
{
    printf("  请重写i2c外设操作\n");
    ret[0] = '\0';
}

// 构造函数
void I2cRead(struct I2cRead *this)
{
    this->Read = Read;
    this->AdapterOperation = AdapterOperation;
    this->ClientOperation = ClientOperation;
}

// 析构函数
void _I2cRead(struct I2cRead *this)
{
    this->Read = NULL;
    this->AdapterOperation = NULL;
    this->ClientOperation = NULL;
}

RtcI2cRead código de muestra

rtc_i2c_read.h

#include "i2c_read.h"

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

// 析构函数
void _RtcI2cRead(struct I2cRead *this);

rtc_i2c_read.c

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

static void ClientOperation(struct I2cRead *this, char *operationCode, char *ret)
{
    printf("  根据operatinCode执行Rtc读操作:\n");
    printf("  ......\n");
    printf("  返回读Rtc的结果\n");
    strcpy(ret, "时间为8:15:00\n");
}


// 构造函数
void RtcI2cRead(struct I2cRead *this)
{
    I2cRead(this);
    this->ClientOperation = ClientOperation;
}

// 析构函数
void _RtcI2cRead(struct I2cRead *this)
{
    _I2cRead(this);
}

LedI2cRead código de muestra

led_i2c_read.h

#include "i2c_read.h"

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

// 析构函数
void _LedI2cRead(struct I2cRead *this);

led_i2c_read.c

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

static void ClientOperation(struct I2cRead *this, char *operationCode, char *ret)
{
    printf("  根据operatinCode执行Led读操作:\n");
    printf("  ......\n");
    printf("  返回读Led的结果\n");
    strcpy(ret, "Led为关\n");
}

// 构造函数
void LedI2cRead(struct I2cRead *this)
{
    I2cRead(this);
    this->ClientOperation = ClientOperation;
}

// 析构函数
void _LedI2cRead(struct I2cRead *this)
{
    _I2cRead(this);
}

Ejemplo de código de cliente

#include "led_i2c_read.h"
#include "rtc_i2c_read.h"
#include <stdio.h>

void main()
{
    char ret[100];

    printf("读i2c Rtc:\n");
    struct I2cRead rtcRead;
    RtcI2cRead(&rtcRead);
    rtcRead.Read(&rtcRead, "读时间", ret);
    printf("  %s", ret);

    printf("读i2c Led:\n");
    struct I2cRead ledRead;
    LedI2cRead(&ledRead);
    rtcRead.Read(&ledRead, "读状态", ret);
    printf("  %s", ret);
}

Ejemplo de visualización del cliente

-bash-4.2# ./test
读i2c Rtc:
  执行i2c适配器操作
  根据operatinCode执行Rtc读操作:
  ......
  返回读Rtc的结果
  时间为8:15:00
读i2c Led:
  执行i2c适配器操作
  根据operatinCode执行Led读操作:
  ......
  返回读Led的结果
  Led为关

Supongo que te gusta

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