创建型设计模式之建造者模式:
一、含义
建造者模式也叫做生成器模式,其定义如下:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
通俗地说,
建造者通过零件的组装来建造对象,组装顺序不同对象效能也不同(产生不同的对象)
二、代码说明
1.主要有三个角色
1)产品类角色
通常实现了模版方法模式,也就是有模版方法和基本方法
2)建造者角色
规范产品的组建,并且返回一个组建好的对象
3)导演类角色
负责安排已有模块的顺序,然后告诉建造者开始建造。
导演类起到封装的作用,避免高层模块深入到建造者内部的实现类。当然,在建造者模式比较庞大时,导演类可以有多个。
2.在用C实现过程中也是参考这种思想,以创造各种超人举例,具体实现如下:
1)建造者模式使用场景:
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : BuilderPatternUsage.c 5 * Description : 建造者模式的使用 6 7 book@book-desktop:/work/projects/test/DesignPatterns/BuilderPattern$ gcc -o BuilderPatternUsage SuperMan.c AdultSuperManBuilder.c Builder.c ChildSuperManBuilder.c BuilderPattern.c BuilderPatternUsage.c 8 book@book-desktop:/work/projects/test/DesignPatterns/BuilderPattern$ ./BuilderPatternUsage 9 ------------创造成年超人:------------ 10 成年超人的天赋是:刀枪不入 11 -----------创造未成年超人:----------- 12 未成年超人的天赋是:会飞行 13 14 * Created : 2017.08.01. 15 * Author : Yu Weifeng 16 * Function List : 17 * Last Modified : 18 * History : 19 ******************************************************************************/ 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include "BuilderPattern.h" 24 25 26 27 28 /***************************************************************************** 29 -Fuction : main 30 -Description : 31 -Input : 32 -Output : 33 -Return : 34 * Modify Date Version Author Modification 35 * ----------------------------------------------- 36 * 2017/08/01 V1.0.0 Yu Weifeng Created 37 ******************************************************************************/ 38 int main(int argc,char **argv) 39 { 40 printf("------------创造成年超人:------------ "); 41 T_SuperMan tAdultSuperMan=g_tDirector.GetAdultSuperMan(); 42 printf("成年超人的天赋是:%s ",tAdultSuperMan.GetSpecialTalent(&tAdultSuperMan)); 43 44 printf("-----------创造未成年超人:----------- "); 45 T_SuperMan tChildSuperMan=g_tDirector.GetChildSuperMan(); 46 printf("未成年超人的天赋是:%s ",tChildSuperMan.GetSpecialTalent(&tChildSuperMan)); 47 48 return 0; 49 }
2)被调用者:
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : BuilderPattern.c 5 * Description : 建造者模式 6 本文件是导演类的具体实现 7 以创造各种超人举例 8 9 * Created : 2017.08.01. 10 * Author : Yu Weifeng 11 * Function List : 12 * Last Modified : 13 * History : 14 ******************************************************************************/ 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include "BuilderPattern.h" 19 20 void SuperManSetBody(T_SuperMan *ptThis,char *i_strBody); 21 char * SuperManGetBody(T_SuperMan *ptThis); 22 void SuperManSetSpecialTalent(T_SuperMan *ptThis,char *i_strSpecialTalent); 23 char * SuperManGetSpecialTalent(T_SuperMan *ptThis); 24 void SuperManSetSpecialSymbol(T_SuperMan *ptThis,char *i_strSpecialSymbol); 25 char * SuperManGetSpecialSymbol(T_SuperMan *ptThis); 26 #define newSuperMan {NULL,NULL,NULL,SuperManSetBody,SuperManGetBody,SuperManSetSpecialTalent, 27 SuperManGetSpecialTalent,SuperManSetSpecialSymbol,SuperManGetSpecialSymbol} 28 29 void BuilderSetBody(T_Builder *ptThis,char *i_strBody); 30 void BuilderSetSpecialTalent(T_Builder *ptThis,char *i_strSpecialTalent); 31 void BuilderSetSpecialSymbol(T_Builder *ptThis,char *i_strSpecialSymbol); 32 33 T_SuperMan AdultBuilderGetSuperMan(T_Builder *ptThis); 34 #define newAdultBuilder {newSuperMan,BuilderSetBody,BuilderSetSpecialTalent,BuilderSetSpecialSymbol,AdultBuilderGetSuperMan} 35 36 T_SuperMan ChildBuilderGetSuperMan(T_Builder *ptThis); 37 #define newChildBuilder {newSuperMan,BuilderSetBody,BuilderSetSpecialTalent,BuilderSetSpecialSymbol,ChildBuilderGetSuperMan} 38 39 40 static T_Builder g_tAdultBuilder=newAdultBuilder; 41 static T_Builder g_tChildBuilder=newChildBuilder; 42 static T_SuperMan GetAdultSuperMan(); 43 static T_SuperMan GetChildSuperMan(); 44 const T_Director g_tDirector={ 45 .GetAdultSuperMan=GetAdultSuperMan, 46 .GetChildSuperMan=GetChildSuperMan, 47 }; 48 49 50 51 /***************************************************************************** 52 -Fuction : GetAdultSuperMan 53 -Description : 54 -Input : 55 -Output : 56 -Return : 57 * Modify Date Version Author Modification 58 * ----------------------------------------------- 59 * 2017/08/01 V1.0.0 Yu Weifeng Created 60 ******************************************************************************/ 61 static T_SuperMan GetAdultSuperMan() 62 { 63 return g_tAdultBuilder.GetSuperMan(&g_tAdultBuilder); 64 } 65 66 /***************************************************************************** 67 -Fuction : GetChildSuperMan 68 -Description : 69 -Input : 70 -Output : 71 -Return : 72 * Modify Date Version Author Modification 73 * ----------------------------------------------- 74 * 2017/08/01 V1.0.0 Yu Weifeng Created 75 ******************************************************************************/ 76 static T_SuperMan GetChildSuperMan() 77 { 78 return g_tChildBuilder.GetSuperMan(&g_tChildBuilder); 79 }
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : BuilderPattern.h 5 * Description : 建造者模式 6 7 * Created : 2017.08.01. 8 * Author : Yu Weifeng 9 * Function List : 10 * Last Modified : 11 * History : 12 ******************************************************************************/ 13 #ifndef BUILDER_PATTERN_H 14 #define BUILDER_PATTERN_H 15 16 typedef struct SuperMan 17 { 18 char *strBody;//私有变量,禁止直接访问 19 char *strSpecialTalent;//私有变量,禁止直接访问 20 char *strSpecialSymbol;//私有变量,禁止直接访问 21 void (*SetBody)(struct SuperMan *ptThis,char *i_strBody); 22 char * (*GetBody)(struct SuperMan *ptThis); 23 void (*SetSpecialTalent)(struct SuperMan *ptThis,char *i_strSpecialTalent); 24 char * (*GetSpecialTalent)(struct SuperMan *ptThis); 25 void (*SetSpecialSymbol)(struct SuperMan *ptThis,char *i_strSpecialSymbol); 26 char * (*GetSpecialSymbol)(struct SuperMan *ptThis); 27 }T_SuperMan; 28 29 typedef struct Builder 30 { 31 T_SuperMan tSuperMan; 32 void (*SetBody)(struct Builder *ptThis,char *i_strBody); 33 void (*SetSpecialTalent)(struct Builder *ptThis,char *i_strSpecialTalent); 34 void (*SetSpecialSymbol)(struct Builder *ptThis,char *i_strSpecialSymbol); 35 T_SuperMan (*GetSuperMan)(struct Builder *ptThis); 36 }T_Builder; 37 38 typedef struct Director 39 { 40 T_SuperMan (*GetAdultSuperMan)(); 41 T_SuperMan (*GetChildSuperMan)(); 42 }T_Director; 43 44 const T_Director g_tDirector; 45 46 47 #endif
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : SuperMan.c 5 * Description : 建造者模式 6 本文件是超人的具体实现 7 8 * Created : 2017.08.01. 9 * Author : Yu Weifeng 10 * Function List : 11 * Last Modified : 12 * History : 13 ******************************************************************************/ 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include "BuilderPattern.h" 18 19 20 21 /***************************************************************************** 22 -Fuction : SuperManSetBody 23 -Description : 公有函数 24 -Input : 25 -Output : 26 -Return : 27 * Modify Date Version Author Modification 28 * ----------------------------------------------- 29 * 2017/08/01 V1.0.0 Yu Weifeng Created 30 ******************************************************************************/ 31 void SuperManSetBody(T_SuperMan *ptThis,char *i_strBody) 32 { 33 ptThis->strBody=i_strBody; 34 } 35 36 /***************************************************************************** 37 -Fuction : SuperManGetBody 38 -Description : 公有函数 39 -Input : 40 -Output : 41 -Return : 42 * Modify Date Version Author Modification 43 * ----------------------------------------------- 44 * 2017/08/01 V1.0.0 Yu Weifeng Created 45 ******************************************************************************/ 46 char * SuperManGetBody(T_SuperMan *ptThis) 47 { 48 return ptThis->strBody; 49 } 50 /***************************************************************************** 51 -Fuction : SuperManSetBody 52 -Description : 公有函数 53 -Input : 54 -Output : 55 -Return : 56 * Modify Date Version Author Modification 57 * ----------------------------------------------- 58 * 2017/08/01 V1.0.0 Yu Weifeng Created 59 ******************************************************************************/ 60 void SuperManSetSpecialTalent(T_SuperMan *ptThis,char *i_strSpecialTalent) 61 { 62 ptThis->strSpecialTalent=i_strSpecialTalent; 63 } 64 65 /***************************************************************************** 66 -Fuction : SuperManGetBody 67 -Description : 公有函数 68 -Input : 69 -Output : 70 -Return : 71 * Modify Date Version Author Modification 72 * ----------------------------------------------- 73 * 2017/08/01 V1.0.0 Yu Weifeng Created 74 ******************************************************************************/ 75 char * SuperManGetSpecialTalent(T_SuperMan *ptThis) 76 { 77 return ptThis->strSpecialTalent; 78 } 79 /***************************************************************************** 80 -Fuction : SuperManSetBody 81 -Description : 公有函数 82 -Input : 83 -Output : 84 -Return : 85 * Modify Date Version Author Modification 86 * ----------------------------------------------- 87 * 2017/08/01 V1.0.0 Yu Weifeng Created 88 ******************************************************************************/ 89 void SuperManSetSpecialSymbol(T_SuperMan *ptThis,char *i_strSpecialSymbol) 90 { 91 ptThis->strSpecialSymbol=i_strSpecialSymbol; 92 } 93 94 /***************************************************************************** 95 -Fuction : SuperManGetBody 96 -Description : 公有函数 97 -Input : 98 -Output : 99 -Return : 100 * Modify Date Version Author Modification 101 * ----------------------------------------------- 102 * 2017/08/01 V1.0.0 Yu Weifeng Created 103 ******************************************************************************/ 104 char * SuperManGetSpecialSymbol(T_SuperMan *ptThis) 105 { 106 return ptThis->strSpecialSymbol; 107 }
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : Builder.c 5 * Description : 建造者模式 6 本文件是建造者的具体实现 7 8 * Created : 2017.08.01. 9 * Author : Yu Weifeng 10 * Function List : 11 * Last Modified : 12 * History : 13 ******************************************************************************/ 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include "BuilderPattern.h" 18 19 20 21 /***************************************************************************** 22 -Fuction : BuilderSetBody 23 -Description : 公有函数 24 -Input : 25 -Output : 26 -Return : 27 * Modify Date Version Author Modification 28 * ----------------------------------------------- 29 * 2017/08/01 V1.0.0 Yu Weifeng Created 30 ******************************************************************************/ 31 void BuilderSetBody(T_Builder *ptThis,char *i_strBody) 32 { 33 ptThis->tSuperMan.SetBody(&ptThis->tSuperMan,i_strBody); 34 } 35 36 /***************************************************************************** 37 -Fuction : BuilderSetSpecialTalent 38 -Description : 公有函数 39 -Input : 40 -Output : 41 -Return : 42 * Modify Date Version Author Modification 43 * ----------------------------------------------- 44 * 2017/08/01 V1.0.0 Yu Weifeng Created 45 ******************************************************************************/ 46 void BuilderSetSpecialTalent(T_Builder *ptThis,char *i_strSpecialTalent) 47 { 48 ptThis->tSuperMan.SetSpecialTalent(&ptThis->tSuperMan,i_strSpecialTalent); 49 } 50 51 /***************************************************************************** 52 -Fuction : BuilderSetSpecialSymbol 53 -Description : 公有函数 54 -Input : 55 -Output : 56 -Return : 57 * Modify Date Version Author Modification 58 * ----------------------------------------------- 59 * 2017/08/01 V1.0.0 Yu Weifeng Created 60 ******************************************************************************/ 61 void BuilderSetSpecialSymbol(T_Builder *ptThis,char *i_strSpecialSymbol) 62 { 63 ptThis->tSuperMan.SetSpecialSymbol(&ptThis->tSuperMan,i_strSpecialSymbol); 64 }
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : AdultSuperManBuilder.c 5 * Description : 建造者模式 6 本文件是成年超人建造者的具体实现 7 8 * Created : 2017.08.01. 9 * Author : Yu Weifeng 10 * Function List : 11 * Last Modified : 12 * History : 13 ******************************************************************************/ 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include "BuilderPattern.h" 18 19 20 21 /***************************************************************************** 22 -Fuction : AdultBuilderGetSuperMan 23 -Description : 公有函数 24 -Input : 25 -Output : 26 -Return : 27 * Modify Date Version Author Modification 28 * ----------------------------------------------- 29 * 2017/08/01 V1.0.0 Yu Weifeng Created 30 ******************************************************************************/ 31 T_SuperMan AdultBuilderGetSuperMan(T_Builder *ptThis) 32 { 33 ptThis->SetBody(ptThis,"强壮的躯体"); 34 ptThis->SetSpecialTalent(ptThis,"刀枪不入"); 35 ptThis->SetSpecialSymbol(ptThis,"胸前带小S标记"); 36 return ptThis->tSuperMan; 37 }
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : ChildSuperManBuilder.c 5 * Description : 建造者模式 6 本文件是未成年超人建造者的具体实现 7 8 * Created : 2017.08.01. 9 * Author : Yu Weifeng 10 * Function List : 11 * Last Modified : 12 * History : 13 ******************************************************************************/ 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include "BuilderPattern.h" 18 19 20 21 /***************************************************************************** 22 -Fuction : ChildBuilderGetSuperMan 23 -Description : 公有函数 24 -Input : 25 -Output : 26 -Return : 27 * Modify Date Version Author Modification 28 * ----------------------------------------------- 29 * 2017/08/01 V1.0.0 Yu Weifeng Created 30 ******************************************************************************/ 31 T_SuperMan ChildBuilderGetSuperMan(T_Builder *ptThis) 32 { 33 ptThis->SetBody(ptThis,"强壮的躯体"); 34 ptThis->SetSpecialTalent(ptThis,"会飞行"); 35 ptThis->SetSpecialSymbol(ptThis,"胸前带S标记"); 36 return ptThis->tSuperMan; 37 }
3)执行结果:
book@book-desktop:/work/projects/test/DesignPatterns/BuilderPattern$ gcc -o BuilderPatternUsage SuperMan.c AdultSuperManBuilder.c Builder.c ChildSuperManBuilder.c BuilderPattern.c BuilderPatternUsage.c
book@book-desktop:/work/projects/test/DesignPatterns/BuilderPattern$ ./BuilderPatternUsage
------------创造成年超人:------------
成年超人的天赋是:刀枪不入
-----------创造未成年超人:-----------
未成年超人的天赋是:会飞行
4)详细代码:
https://github.com/fengweiyu/DesignThinking/tree/master/DesignPatterns/CreationalDesignPatterns/BuilderPattern
三、使用场景
1.相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式。
2.多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。
3.产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常适合。
4.在对象创建过程中会使用到系统中的一些其他对象,这些对象在产品对象的创建过程中不易得到时,也可以采用建造者模式封装该对象的创建过程。
这种场景只能是一个补偿方法,因为一个对象不容易获得,在设计阶段竟然没有发觉,本身已经违反设计的最初目标。
四、优点
1.封装性
使用建造者模式可以使客户端不必知道产品内部组成的细节
2.建造者独立,容易扩展
建造者相互对立的,对系统的扩展非常有利。
3.便于控制细节风险
由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。
五、建造者模式的扩展
1.建造者组装零件,组装顺序不同对象效能也不同,(产品类中)引入模版方法模式能更好地达到这种效果,也是一个非常简单而有效的办法。
六、与其他模式的区别
1、建造者模式与工厂方法模式
工厂方法模式注重的是整体对象的创建方法,而建造者模式注重的是部件构建的过程。具体来说,
1)意图不同
在工厂方法模式里,我们关注的是一个产品整体;但在建造这模式中,关注的是 由零件一步一步地组装出产品对象。
简单的说,工厂模式是一个对象创建的粗线条应用,建造者模式则是通过细线条勾勒出一个复杂对象,关注的是产品组成部分的创建过程。
2)产品的复杂度不同
工厂方法模式创建的产品一般都是单一性质产品,都是一个模样;而建造者模式创建的则是一个复合产品,它由各个部件复合而成,部件不同产品对象当然不同。这不是说工厂方法模式创建的对象简单,而是指它们的粒度大小不同。一般来说工厂方法模式的对象粒度比较粗,建造者模式的产品对象粒度比较细。
两种模式的选择,完全取决于在做系统设计时的意图,如果需要详细关注一个产品部件的生产、安装步骤,则选择建造者,否则选择工厂方法模式。
2、建造者模式与抽象工厂模式
抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式则是不需要关系构建过程,只关心什么产品由什么工厂生成即可。
而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品,两者的区别还是比较明显的。
具体来说,
1)抽象工厂模式就好比是一个一个的工厂,对外界来说,只要关心一个工厂到底是生产什么产品的,不用关心具体怎么生产。
而建造者模式就不同了,它是由车间组成,不同的车间完成不同的创建和装配任务,车间主任(导演类)给建造车间什么蓝图就能生产什么产品,建造者模式更关心建造过程。
2)相对来说,抽象工厂模式比建造者模式的尺度要大,它关注产品整体,而建造者模式关注构建过程,因此建造者模式可以很容易地构建出一个崭新的产品,只要导演类能够提供具体的工艺流程。
3)两者的应用场景截然不同,如果希望屏蔽对象的创建过程,只提供一个封装良好的对象,则可以选择抽象工厂方法模式。
而建造者模式可以用在构件的装配方面,如通过装配不同的组件或相同组件的不同顺序,可以产生出一个新的对象,它可以产生一个非常灵活的架构,方便地扩展和维护系统。