大话设计模式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);
void server_config_destroy(ServerConfig *cfg);
#endif
|
产品内部接口 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"
ServerConfig *server_config_create_internal( char *host, int port, int timeout, int max_connections, int enable_tls);
#endif
|
产品实现 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;
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);
ServerConfig *server_config_builder_build(ServerConfigBuilder *builder);
#endif
|
建造器实现 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; }
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.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)” 的出现。假设你的构造函数中有十个可选参数, 那么调用该函数会非常不方便,生成器模式让你可以分步骤生成对象, 而且允许你仅使用必须的步骤。 应用该模式后, 你再也不需要将几十个参数塞进构造函数里了。或当你希望使用代码创建不同形式的产品(例如石头或木头房屋)时,可使用生成器模式。如果你需要创建的各种形式的产品, 它们的制造过程相似且仅有细节上的差异, 此时可使用生成器模式。基本生成器接口中定义了所有可能的制造步骤,具体生成器将实现这些步骤来制造特定形式的产品。同时主管类将负责管理制造步骤的顺序。