大话设计模式C语言之模板模式

模板模式

模板方法 (Template Method) 模式:在基类中定义算法骨架,将某些步骤延迟到子类实现,使子类在不改变算法结构的情况下重新定义算法的某些步骤。

案例代码

  这里举了数据处理模板的例子,在基类中定义了数据处理模板,将数据处理的具体步骤延迟到文件数据处理与网络数据处理两个子类实现,使子类在不改变数据处理模板的情况下重新定义数据处理的具体步骤。

案例代码

抽象基类 data_processor.h

抽象类(Abstract­Class)会声明作为算法步骤的方法,以及依次调用它们的实际模板方法。算法步骤可以被声明为抽象类型,也可以提供一些默认实现。

  模型模式通过结构体内的函数指针定义了类中必须实现和可选实现的抽象方法步骤,以及声明了通用的算法模板。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ifndef DATA_PROCESSOR_H
#define DATA_PROCESSOR_H

typedef struct DataProcessor DataProcessor;

/* 抽象步骤 */
typedef struct
{
int (*open)(DataProcessor *self);
int (*read)(DataProcessor *self);
int (*process)(DataProcessor *self);
void (*close)(DataProcessor *self);

/* Hook:可选步骤 */
int (*need_validate)(DataProcessor *self);
int (*validate)(DataProcessor *self);
} DataProcessorOps;

struct DataProcessor
{
const DataProcessorOps *ops;
};

/* 模板方法:固定算法骨架 */
int data_processor_execute(DataProcessor *self);

#endif // DATA_PROCESSOR_H

抽象基类模板实现 data_processor.c

  实现了抽象基类的模板,定义了数据处理的固定流程。这个设计允许具体的数据处理器实现ops 结构体中的各个操作函数,而流程的整体控制逻辑保持不变。钩子机制让子类可以选择性地进行验证操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
#include "data_processor.h"

int data_processor_execute(DataProcessor *self)
{
if (!self || !self->ops)
return -1;

if (self->ops->open(self) != 0)
return -1;

if (self->ops->read(self) != 0)
goto error;

if (self->ops->process(self) != 0)
goto error;

/* Hook */
if (self->ops->need_validate &&
self->ops->need_validate(self))
{

if (!self->ops->validate ||
self->ops->validate(self) != 0)
{
goto error;
}
}

self->ops->close(self);
return 0;

error:
self->ops->close(self);
return -1;
}

具体实现-文件处理器接口 file_processor.h

1
2
3
4
5
6
7
8
9
10
#ifndef FILE_PROCESSOR_H
#define FILE_PROCESSOR_H

#include "data_processor.h"

DataProcessor *file_processor_create(const char *path);
void file_processor_destroy(DataProcessor *processor);

#endif // FILE_PROCESSOR_H

具体实现-文件处理器实现 file_processor.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include "file_processor.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
DataProcessor base;
char *path;
} FileProcessor;

static int file_open(DataProcessor *self) {
FileProcessor *fp = (FileProcessor *)self;
printf("File open: %s\n", fp->path);
return 0;
}

static int file_read(DataProcessor *self) {
(void)self;
printf("File read\n");
return 0;
}

static int file_process(DataProcessor *self) {
(void)self;
printf("File process\n");
return 0;
}

static int file_need_validate(DataProcessor *self) {
(void)self;
return 1; /* 需要校验 */
}

static int file_validate(DataProcessor *self) {
(void)self;
printf("File validate\n");
return 0;
}

static void file_close(DataProcessor *self) {
(void)self;
printf("File close\n");
}

static const DataProcessorOps file_ops = {
.open = file_open,
.read = file_read,
.process = file_process,
.close = file_close,
.need_validate = file_need_validate,
.validate = file_validate
};

DataProcessor *file_processor_create(const char *path) {
FileProcessor *fp = malloc(sizeof(*fp));
if (!fp) return NULL;

fp->base.ops = &file_ops;
fp->path = strdup(path);
return &fp->base;
}

void file_processor_destroy(DataProcessor *processor) {
FileProcessor *fp = (FileProcessor *)processor;
free(fp->path);
free(fp);
}

具体实现-网络处理器接口 network_processor.h

1
2
3
4
5
6
7
8
9
10
#ifndef NETWORK_PROCESSOR_H
#define NETWORK_PROCESSOR_H

#include "data_processor.h"

DataProcessor *network_processor_create(int port);
void network_processor_destroy(DataProcessor *processor);

#endif // NETWORK_PROCESSOR_H

具体实现-网络处理器实现 network_processor.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include "network_processor.h"
#include <stdio.h>
#include <stdlib.h>

typedef struct {
DataProcessor base;
int port;
} NetworkProcessor;

static int net_open(DataProcessor *self) {
NetworkProcessor *np = (NetworkProcessor *)self;
printf("Network open on port %d\n", np->port);
return 0;
}

static int net_read(DataProcessor *self) {
(void)self;
printf("Network read\n");
return 0;
}

static int net_process(DataProcessor *self) {
(void)self;
printf("Network process\n");
return 0;
}

static void net_close(DataProcessor *self) {
(void)self;
printf("Network close\n");
}

static const DataProcessorOps net_ops = {
.open = net_open,
.read = net_read,
.process = net_process,
.close = net_close,
.need_validate = NULL,
.validate = NULL
};

DataProcessor *network_processor_create(int port) {
NetworkProcessor *np = malloc(sizeof(*np));
if (!np) return NULL;

np->base.ops = &net_ops;
np->port = port;
return &np->base;
}

void network_processor_destroy(DataProcessor *processor) {
free(processor);
}

测试代码 main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "file_processor.h"
#include "network_processor.h"
#include <stdio.h>

int main(void)
{
DataProcessor *file =
file_processor_create("data.txt");

DataProcessor *net =
network_processor_create(8080);

data_processor_execute(file);
printf("--------------------------\n");
data_processor_execute(net);

file_processor_destroy(file);
network_processor_destroy(net);

while (1);
return 0;
}

总结

  模板方法模式是通过把不变的行为搬到基类,去除子类中的重复代码来体现他的优势,提供了一个很好的代码复用平台。工厂方法模式是模板方法模式的一种特殊形式。同时工厂方法可以作为一个大型模板方法中的一个步骤。