用C语言编写建造者模式

编程语言及工具

102人已加入

描述

/ 一、简介 /

建造者模式: 也称生成器模式,是 23 种设计模式中的一种,是一种创建型模式。适用情况:一个对象比较复杂,将一个对象的构建和对象的表示进行分离。

比较:与工厂模式进行对比,工厂模式不考虑对象部件组装过程,直接生成一个最终的对象,强调的是 结果 。而建造者模式先构建对象的每一个部件,然后再统一组建成一个对象,强调的是 过程

目的:实现复杂对象的生产流程与部件进行解耦。

/ 二、设计实现 /

以建造房子为例,房子有公寓、别墅、楼房等类型,虽然是不同种类的房子,但其建造过程大体上都相同,例如都有这些流程:修建墙、窗户、门、地板、楼顶等。

我们实现 Builder( 建造者 )建房,因为都有修建(墙、窗户、门、楼等)这些 部件 ,但是具体实现却不同,所以我们需要把实现这些组建的操作给抽象出来,把每个部件实现了,然后再组装起来,修建的房子就完成了。

typedef struct IBuilder_t           //建造者抽象接口
{
    void (*make_floor)(void *obj);  //修建地板
    void (*make_door)(void *obj);   //修建门
    void (*make_wall)(void *obj);   //修建墙
    void (*make_window)(void *obj); //修建窗
    void (*destory)(void *obj);     //释放内存
    House_t *house;                 //house对象
}IBuilder_t;

定义房子对象,然后房子里面的部件(墙、窗、门、地板等)交给建造者设置修建。

typedef struct House_t  //定义房子要实现的接口
{
    void (*setfloor)(struct House_t* obj, char *floor);
    void (*setdoor)(struct House_t* obj, char *door);
    void (*setwall)(struct House_t* obj, char *wall);
    void (*setwindow)(struct House_t* obj, char *window);


    char floor[32];         //地板名字
    char door[32];          //门名字
    char wall[32];          //墙名字
    char window[32];        //窗名字
}House_t;


//修建的地板类型。
//static修饰,不让外部直接调用这个函数,
//一般这些函数的实现放到.c文件中,结构体定义在.h文件中,
//而是通过House_t结构体的setfloor()函数指针进行调用,起到封装效果(下同)。
static void house_setfloor(House_t* obj, char *floor)
{
    if(obj) sprintf(obj- >floor, "%s", floor);
}


//修建的门类型
static void house_setdoor(House_t* obj, char *door)
{
    if(obj) sprintf(obj- >door, "%s", door);
}


//修建的墙类型
static void house_setwall(House_t* obj, char *wall)
{
    if(obj) sprintf(obj- >wall, "%s", wall);
}


//修建的窗类型
static void house_setwindow(House_t* obj, char *window)
{
    if(obj) sprintf(obj- >window, "%s", window);
}


//构造函数 创建一个房子的对象
//此处这个函数不能适用static修饰
//该函数是要开放被外部调用的
House_t* constructor_house(void)
{
    House_t* house = (House_t*)malloc(sizeof(House_t)); //申请对象
    house- >setdoor = house_setdoor;    //函数指针赋值
    house- >setfloor = house_setfloor;  //函数指针赋值
    house- >setwall = house_setwall;    //函数指针赋值  
    house- >setwindow = house_setwindow;//函数指针赋值
    return house;                      //返回一个房子对象
}

接下来我们实现 builder,修建一个 公寓 。注:另外一个修建别墅实现,与修建公寓实现几乎完全一致,此处不做过多阐述。

//建造公寓的结构体,与IBuilder_t定义一致,即对IBuilder_t的实现
typedef struct FlatBuilder_t 
{
    void (*make_floor)(void *obj);
    void (*make_door)(void *obj);
    void (*make_wall)(void *obj);
    void (*make_window)(void *obj);
    void (*destory)(void *obj);
    House_t *house;
}FlatBuilder_t;


//建造地板。static修饰作用同上
static void flat_make_floor(void *obj)
{
    FlatBuilder_t* flat = (FlatBuilder_t*)obj;
    flat- >house- >setfloor(flat- >house, "修建:flat floor");
}
//建造门
static void flat_make_door(void *obj)
{
    FlatBuilder_t* flat = (FlatBuilder_t*)obj;
    flat- >house- >setdoor(flat- >house, "修建:flat door");
}
//建造墙
static void flat_make_wall(void *obj)
{
    FlatBuilder_t* flat = (FlatBuilder_t*)obj;
    flat- >house- >setwall(flat- >house, "修建:flat wall");
}
//建造窗
static void flat_make_window(void *obj)
{
    FlatBuilder_t* flat = (FlatBuilder_t*)obj;
    flat- >house- >setwindow(flat- >house, "修建:flat window");
}
//释放内存的函数
static void flat_destory(void *obj)
{
    FlatBuilder_t* flat = (FlatBuilder_t*)obj;
    if(flat- >house) free(flat- >house); //首先先释放flat包含的house内存
    flat- >house=NULL;
    free(flat);                        //其次再释放当前对象
    flat=NULL;
}


//公寓建造者的构造函数,此处不能采用static修饰,因为其要被外部调用
FlatBuilder_t* constructor_flat_builder(void)
{
    FlatBuilder_t* flat = (FlatBuilder_t*)malloc(sizeof(FlatBuilder_t));
    flat- >house = constructor_house();
    flat- >make_door = flat_make_door;
    flat- >make_floor = flat_make_floor;
    flat- >make_wall = flat_make_wall;
    flat- >make_window = flat_make_window;
    flat- >destory = flat_destory;
    return flat;
}

/ 三、测试 /

main 函数里面的测试代码如下:定义一个 ** IBuilder_t buidler=NULL * ,用它指向不同的建造者,实现修建不同的房子。此时修建公寓和别墅两种不同房子。

int main(void)
{
    House_t *house=NULL;
    IBuilder_t *buidler=NULL;


    //指向公寓建造者,修建公寓
    buidler=(IBuilder_t*)constructor_flat_builder();
    buidler- >make_door(buidler);  //修建公寓的门
    buidler- >make_floor(buidler); //修建公寓的地板
    buidler- >make_wall(buidler);  //修建公寓的墙
    buidler- >make_window(buidler);//修建公寓的窗
    house = buidler- >house;       //拿到修建的好的房子
    printf("%s\\n", house- >door);  //显示公寓门
    printf("%s\\n", house- >floor); //显示公寓地板
    printf("%s\\n", house- >wall);  //显示公寓墙
    printf("%s\\n", house- >window);//显示公寓窗
    buidler- >destory(buidler);    //释放内存
    printf("\\n");


    //指向别墅建造者,修建别墅
    buidler=(IBuilder_t*)constructor_villa_builder();
    buidler- >make_door(buidler);    //修建别墅的门
    buidler- >make_floor(buidler);   //修建别墅的地板
    buidler- >make_wall(buidler);    //修建别墅的墙
    buidler- >make_window(buidler);  //修建别墅的窗
    house = buidler- >house;         //拿到修建好的房子
    printf("%s\\n", house- >door);    //显示别墅门
    printf("%s\\n", house- >floor);   //显示别墅地板
    printf("%s\\n", house- >wall);    //显示别墅墙
    printf("%s\\n", house- >window);  //显示别墅窗
    buidler- >destory(buidler);      //释放内存


    return 0;
}

执行的效果如下图:

生成器

/ 四、总结 /

通过上面的内容,我们了解到建造者模式主要是针对创建对象的过程的,而且还可以控制一个复杂类中部件创建的顺序以及部件创建的内容。提高程序的扩展性,践行“高内聚、低耦合”。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分