14 design pattern _ template method pattern _ C language implementation

Template method pattern

1 Simulation scene

Suppose we are a chip supplier and now we have developed a new CPU. Various bus controllers are integrated on the CPU, such as i2c, spi, usb and so on. In order to allow customers to use our CPU smoothly, we need to provide customers with driver software supporting various bus controllers.

Let's take i2c as an example to see what the driver software we provide to customers as a chip supplier looks like.

(PS: I assume that the reader has a certain understanding of the driver software, so the basic concepts of i2c and driver software will not be explained in this article)

We assume that the pseudo code driven by "i2c read operation" is as follows:

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

I2cAdaptorOperation()
{
    具体实现略   
}

I2cClientOperation()
{
    具体实现略
}

The above is the pseudo code for the entire "i2c read operation" drive. The above pseudo code is divided into three parts:

The first part is I2cAdaptorOperation(). It is the operation of the i2c controller integrated in the CPU. The implementation of this part of the code is our responsibility (ie the chip supplier). Because the i2c controller is implemented by us, we know how to implement the driver of the i2c controller.

The second part is I2cClientOperation(). It is the operation of i2c peripherals. The implementation of this part of the code is the responsibility of the customer. Because customers may use our CPU to connect various i2c peripherals (such as i2c's rtc, i2c's led), we don't know what the customer's peripherals are, so there is no way to implement this part of the code.

The third part is I2cRead(). It is the main flow code of i2c read operation. So is this part of the code implemented by us or by the customer? Both methods are common.

For the way the customer is responsible for implementing I2cRead(): Generally speaking, we (ie, the chip supplier) have clearly defined how I2cRead() should be implemented when designing the i2c controller, and customers often do not know how to implement I2cRead(). Therefore, we generally provide customers with the DEMO code of I2cRead() for reference, and the customer will implement I2cRead() according to the DEMO code.

For the way we (ie the chip supplier) is responsible for implementing I2cRead(): I2cRead() needs to call I2cClientOperation(), and I2cClientOperation() is implemented by the customer. So when we implement I2cRead(), I2cClientOperation() has not yet been implemented. At this time, we can only define the abstract interface of I2cClientOperation(), and call the abstract interface of I2cClientOperation() in I2cRead(), and then the abstract interface of I2cClientOperation() is rewritten by the client.

Here "the way we (ie the chip supplier) is responsible for implementing I2cRead()" is the template method. Let's take this as an example to sort out the idea and implementation of the template method.

2 Introduction to template method

The template method defines the algorithm skeleton of an operation, and delays some steps to subclasses. The template method allows subclasses to redefine certain specific steps of an algorithm without changing the structure of the algorithm.

Corresponds to the above example:

I2cRead() is the skeleton of the algorithm

I2cClientOperation() is the step of delaying to the subclass

3 Use the template method to realize the "i2c read operation" driver for the chip supplier

Participant

  1. AbstractClass: I2cRead

The main flow of the i2c read operation contains the implementation of the methods called in the flow. But the I2cClientOperation() method needs to be rewritten by a specific class.

This part is implemented by the CPU chip supplier that integrates the i2c controller.

  1. ConcreteClass: RtcI2cRead、LedI2cRead

Inherit I2cRead and rewrite I2cClientOperation() according to the specific conditions of the peripherals (rtc, led).

This part is complicatedly realized by customers who purchase CPU chips.

UML

Insert picture description here

I2cRead sample code

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 sample code

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 sample code

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

Client code example

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

Client display example

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

Guess you like

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