大话设计模式C语言之建造模式

建造模式

建造模式 (BuilderPattern) 是一种创建型设计模式,使你能够分步骤创建复杂对象。该模式允许你使用相同的创建代码生成不同类型和形式的对象。

   下面举了一个Director + Builder模式构造不同的 ServerConfig 配置实例,使用director的三个预设方法(build_http / build_https / build_high_perf)并传入同一个builder和不同的host字符串来构建三种配置,然后把各实例的字段打印出来并销毁的例子。

案例代码

产品接口 server_config.h

产品 (Products) 是最终生成的对象。 由不同生成器构造的产品无需属于同一类层次结构或接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

#ifndef SERVER_CONFIG_H
#define SERVER_CONFIG_H

typedef struct ServerConfig ServerConfig;

/* 只读访问接口 */
const char *server_config_host(const ServerConfig *cfg);
int server_config_port(const ServerConfig *cfg);
int server_config_timeout(const ServerConfig *cfg);
int server_config_max_connections(const ServerConfig *cfg);
int server_config_tls_enabled(const ServerConfig *cfg);

/* 销毁 Product */
void server_config_destroy(ServerConfig *cfg);

#endif /* SERVER_CONFIG_H */

产品内部接口 server_config_internal.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

#ifndef SERVER_CONFIG_INTERNAL_H
#define SERVER_CONFIG_INTERNAL_H

#include "server_config.h"

/*
* - 该头文件不对外暴露,使得API 稳定 便于 单测 / 替换
*/

ServerConfig *server_config_create_internal(
char *host,
int port,
int timeout,
int max_connections,
int enable_tls);

#endif /* SERVER_CONFIG_INTERNAL_H */


产品实现 server_config.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
69
70
#include "server_config_internal.h"
#include <stdlib.h>

struct ServerConfig
{
char *host;
int port;
int timeout;
int max_connections;
int enable_tls;
};

ServerConfig *server_config_create_internal(
char *host,
int port,
int timeout,
int max_connections,
int enable_tls)
{

ServerConfig *cfg = calloc(1, sizeof(*cfg));
if (!cfg)
{
return NULL;
}

cfg->host = host; /* 接管所有权 */
cfg->port = port;
cfg->timeout = timeout;
cfg->max_connections = max_connections;
cfg->enable_tls = enable_tls;

return cfg;
}

const char *server_config_host(const ServerConfig *cfg)
{
return cfg ? cfg->host : NULL;
}

int server_config_port(const ServerConfig *cfg)
{
return cfg ? cfg->port : -1;
}

int server_config_timeout(const ServerConfig *cfg)
{
return cfg ? cfg->timeout : -1;
}

int server_config_max_connections(const ServerConfig *cfg)
{
return cfg ? cfg->max_connections : -1;
}

int server_config_tls_enabled(const ServerConfig *cfg)
{
return cfg ? cfg->enable_tls : 0;
}

void server_config_destroy(ServerConfig *cfg)
{
if (!cfg)
{
return;
}
free(cfg->host);
free(cfg);
}

建造器接口 server_config_builder.h

建造器(Builder)接口声明在所有类型生成器中通用的产品构建步骤。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef SERVER_CONFIG_BUILDER_H
#define SERVER_CONFIG_BUILDER_H

#include "server_config.h"

typedef struct ServerConfigBuilder ServerConfigBuilder;

/* Builder 生命周期 */
ServerConfigBuilder *server_config_builder_create(void);
void server_config_builder_destroy(ServerConfigBuilder *builder);

/* 构建步骤 */
int server_config_builder_set_host(ServerConfigBuilder *builder, const char *host);
int server_config_builder_set_port(ServerConfigBuilder *builder, int port);
int server_config_builder_set_timeout(ServerConfigBuilder *builder, int timeout);
int server_config_builder_set_max_connections(ServerConfigBuilder *builder, int max_conn);
int server_config_builder_enable_tls(ServerConfigBuilder *builder, int enable);

/* 构建最终 Product */
ServerConfig *server_config_builder_build(ServerConfigBuilder *builder);

#endif /* SERVER_CONFIG_BUILDER_H */

建造器实现 server_config_builder.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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "server_config_builder.h"
#include "server_config_internal.h"
#include <stdlib.h>
#include <string.h>

struct ServerConfigBuilder
{
char *host;
int port;
int timeout;
int max_connections;
int enable_tls;
int host_set;
};

ServerConfigBuilder *server_config_builder_create(void)
{
ServerConfigBuilder *b = calloc(1, sizeof(*b));
if (!b)
{
return NULL;
}

/* 默认值 */
b->port = 80;
b->timeout = 30;
b->max_connections = 100;
b->enable_tls = 0;

return b;
}

void server_config_builder_destroy(ServerConfigBuilder *b)
{
if (!b)
{
return;
}
free(b->host);
free(b);
}

int server_config_builder_set_host(ServerConfigBuilder *b, const char *host)
{
if (!b || !host)
{
return -1;
}

char *copy = strdup(host);
if (!copy)
{
return -1;
}

free(b->host);
b->host = copy;
b->host_set = 1;
return 0;
}

int server_config_builder_set_port(ServerConfigBuilder *b, int port)
{
if (!b || port <= 0 || port > 65535)
{
return -1;
}
b->port = port;
return 0;
}

int server_config_builder_set_timeout(ServerConfigBuilder *b, int timeout)
{
if (!b || timeout < 0)
{
return -1;
}
b->timeout = timeout;
return 0;
}

int server_config_builder_set_max_connections(ServerConfigBuilder *b, int max_conn)
{
if (!b || max_conn <= 0)
{
return -1;
}
b->max_connections = max_conn;
return 0;
}

int server_config_builder_enable_tls(ServerConfigBuilder *b, int enable)
{
if (!b)
{
return -1;
}
b->enable_tls = enable ? 1 : 0;
return 0;
}

ServerConfig *server_config_builder_build(ServerConfigBuilder *b)
{
if (!b || !b->host_set)
{
return NULL;
}

ServerConfig *cfg =
server_config_create_internal(
b->host,
b->port,
b->timeout,
b->max_connections,
b->enable_tls);

if (!cfg)
{
return NULL;
}

/* 转移所有权后清空 Builder */
b->host = NULL;
b->host_set = 0;

return cfg;
}

主管类接口 server_config_director.h

主管 Director)类定义调用构造步骤的顺序,这样你就可以创建和复用特定的产品配置。

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
#ifndef SERVER_CONFIG_DIRECTOR_H
#define SERVER_CONFIG_DIRECTOR_H

#include "server_config_builder.h"

typedef struct ServerConfigDirector ServerConfigDirector;

ServerConfigDirector *server_config_director_create(void);
void server_config_director_destroy(ServerConfigDirector *director);

ServerConfig *server_config_director_build_http(
ServerConfigDirector *director,
ServerConfigBuilder *builder,
const char *host);

ServerConfig *server_config_director_build_https(
ServerConfigDirector *director,
ServerConfigBuilder *builder,
const char *host);

ServerConfig *server_config_director_build_high_perf(
ServerConfigDirector *director,
ServerConfigBuilder *builder,
const char *host);

#endif /* SERVER_CONFIG_DIRECTOR_H */

主管类实现 server_config_director.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
#include "server_config_director.h"
#include <stdlib.h>

struct ServerConfigDirector
{
int reserved;
};

ServerConfigDirector *server_config_director_create(void)
{
return calloc(1, sizeof(ServerConfigDirector));
}

void server_config_director_destroy(ServerConfigDirector *director)
{
free(director);
}

ServerConfig *server_config_director_build_http(
ServerConfigDirector *director,
ServerConfigBuilder *builder,
const char *host)
{

(void)director;

server_config_builder_set_host(builder, host);
server_config_builder_set_port(builder, 80);
server_config_builder_enable_tls(builder, 0);

return server_config_builder_build(builder);
}

ServerConfig *server_config_director_build_https(
ServerConfigDirector *director,
ServerConfigBuilder *builder,
const char *host)
{

(void)director;

server_config_builder_set_host(builder, host);
server_config_builder_set_port(builder, 443);
server_config_builder_set_timeout(builder, 60);
server_config_builder_enable_tls(builder, 1);

return server_config_builder_build(builder);
}

ServerConfig *server_config_director_build_high_perf(
ServerConfigDirector *director,
ServerConfigBuilder *builder,
const char *host)
{

(void)director;

server_config_builder_set_host(builder, host);
server_config_builder_set_port(builder, 8080);
server_config_builder_set_timeout(builder, 10);
server_config_builder_set_max_connections(builder, 10000);
server_config_builder_enable_tls(builder, 0);

return server_config_builder_build(builder);
}

测试客户端代码 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
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
#include "server_config_director.h"

static void dump(const ServerConfig *cfg)
{
printf("host=%s port=%d timeout=%d max_conn=%d tls=%d\n",
server_config_host(cfg),
server_config_port(cfg),
server_config_timeout(cfg),
server_config_max_connections(cfg),
server_config_tls_enabled(cfg));
}

int main(void)
{
ServerConfigBuilder *builder = server_config_builder_create();
ServerConfigDirector *director = server_config_director_create();

ServerConfig *http = server_config_director_build_http(director, builder, "example.com");
dump(http);
server_config_destroy(http);

ServerConfig *https = server_config_director_build_https(director, builder, "secure.com");
dump(https);
server_config_destroy(https);

ServerConfig *high = server_config_director_build_high_perf(director, builder, "fast.com");
dump(high);
server_config_destroy(high);

server_config_builder_destroy(builder);
server_config_director_destroy(director);

while (1);
return 0;
}

总结

   建造者模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式使得我们可以创建复杂对象,而不需要知道其内部的具体构造细节。使用生成器模式可避免 “重叠构造函数(telescoping constructor)” 的出现。假设你的构造函数中有十个可选参数, 那么调用该函数会非常不方便,生成器模式让你可以分步骤生成对象, 而且允许你仅使用必须的步骤。 应用该模式后, 你再也不需要将几十个参数塞进构造函数里了。或当你希望使用代码创建不同形式的产品(例如石头或木头房屋)时,可使用生成器模式。如果你需要创建的各种形式的产品, 它们的制造过程相似且仅有细节上的差异, 此时可使用生成器模式。基本生成器接口中定义了所有可能的制造步骤,具体生成器将实现这些步骤来制造特定形式的产品。同时主管类将负责管理制造步骤的顺序。