设计模式读书笔记6--建造者模式

建造者模式又称为生成器模式,它是一种较为复杂、使用频率也相对较低的创建型模式。建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品。因为,没有人买车会只买一个方向盘或者轮胎,大家买的都是一辆包含轮胎、方向盘和发动机等多个部件组成的完整汽车。如何将这些部件组装成一辆完整的汽车并返回给用户,这是建造者模式需要解决的问题。

建造者模式(Builder)  学习难度:★★★★☆  使用频率:★★☆☆☆

1 从变化说起

上节我们谈论了模板方法模型,满足了客户对于汽车模型的需求,但是客户需要增加一个新的需求:汽车的启动,停止,喇叭声音,引擎声音都需要由客户控制,想什么顺序就什么顺序。

我们生产N多奔驰和宝马车型模式,这些车辆模型都有run方法,但是具体到每一个模型的run方法中建的执行顺序是不同,先从简单的切入点,每个车都是一个产品,都有模型方法模式基本的方法。
在CarlModel中我们定义了一个setSequence方法,车辆模型的这几个动作要如何排布,是在这个ArrayList中定义,然后run()方法根据sequeuence定义的顺序完成指定的顺序动作,建造者模型就诞生了。
70

2 建造者模式概述

2.1 定义

建造者模式(Builder):将一个复杂对象的构建与它的表示相分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。

 建造者模式是一种较为复杂的创建型模式,他将客户端与包含多个组成部分的复杂对象的创建过程分离,客户端无需知道复杂对象的内部组成与装配方式,主需要知道所需的建造者即可。其关注点在于如何一步一步地创建一个复杂对象,不同的具体建造者定义了不同的创建过程,且具体建造者相互独立,增加新的建造者非常方便,无需修改已有代码,系统具有较好的可扩展性。
建造者模式通用类如图:
20160505210036657

如上图,建造者模型有4个角色:

  1. Product产品类,通常是实现了模板方法模式,额就是由模板方法和基本方法,后面例子中的BenzModel和BmwModel属于产品类
  2. Builder抽象建造者,一般是由子类实现,例子中的CarBuilder就属于抽象建造者
  3. ConcreteBuilder具体的建造者,实现抽象类定义的所有方法,并且返回一个组建好的对象,例子中的BenzBuilder和BmwBuilder就属于具体的建造者
  4. Director导演类,辅助安排已有模块的顺序,然后开始告诉Builder建造

2.2 实现

建造者模式的比较简单,下面我们来看看对于上面实现方式

2.2.1 Product产品类

/* Product产品抽象类 */
typedef struct _CarModel CarModel;
struct _CarModel
{
    unsigned char *pSequence;

    void (*start)(void);
    void (*stop)(void);
    void (*alarm)(void);
    void (*engineBoom)(void);
    void (*run)(CarModel *pCarModel);
    void (*setSequence)(unsigned char *pParam1, unsigned char *pParam2,
        unsigned char *pParam3, unsigned char *pParam4);

    void (*DeleteCarlModel)(CarModel *pCarModel);
};

Product产品抽象实现:

#include "Builder.h"

void run(CarModel *pCarModel)
{
    int i = 0;
    //unsigned char *pTmp = (unsigned char *)pCarModel->Sequence;
    for(i = 0; i < SEQUENCE_SIZE; i++)
    {
        if(0 == strcmp(pCarModel->Sequence[i], "start"))
        {
            pCarModel->start();
        }
        else if(0 == strcmp(pCarModel->Sequence[i], "stop"))
        {
            pCarModel->stop();
        }
        else if(0 == strcmp(pCarModel->Sequence[i], "alarm"))
        {
            pCarModel->alarm();
        }
        else if(0 == strcmp(pCarModel->Sequence[i], "engineBoom"))
        {
            pCarModel->engineBoom();
        }
        else
        {
            printf("car not run this mode\n");
        }
        // pTmp += SEQUENCE_STRINGLEN;
    }
}

void setSequence(unsigned char *pParam1, unsigned char *pParam2,
unsigned char *pParam3, unsigned char *pParam4)
{
    memset(g_ucSequence, 0, sizeof(g_ucSequence));
    strcpy(g_ucSequence[0], pParam1);
    strcpy(g_ucSequence[1], pParam2);
    strcpy(g_ucSequence[2], pParam3);
    strcpy(g_ucSequence[3], pParam4);
    return;
}

void DeleteCarModel(CarModel *pCarModel)
{
    if(NULL != pCarModel)
    {
        free(pCarModel);
        pCarModel = NULL;
    }
}


CarModel *CreateCarModel(void)
{
    CarModel *pCarModel = (CarModel *)malloc(sizeof(CarModel));
    if(!pCarModel)
    {
        return NULL;
    }
    memset(pCarModel, 0, sizeof(CarModel));
    pCarModel->Sequence       = g_ucSequence;
    pCarModel->DeleteCarlModel = DeleteCarModel;
    pCarModel->run             = run;
    pCarModel->setSequence     = setSequence;

    return pCarModel;
}

下面的BMW和BENZ会根据这个抽象建造者类来构造自己实际的产品类

/* 具体产品类 */
typedef struct _BenzModel BenzModel;
struct _BenzModel
{
    CarModel carModel;
};

typedef struct _BmwModel BmwModel;
struct _BmwModel
{
    CarModel carModel;
};

产品类具体实现

#include "Builder.h"

void BenzAlarm(void)
{
    printf("Benz alarm\n");
}

void BenzEngineBoom(void)
{
    printf("Benz engineBoom\n");
}

void BenzStart(void)
{
    printf("Benz start\n");
}

void BenzStop(void)
{
    printf("Benz stop\n");
}

BenzModel *CreateBenzModel(void)
{
    BenzModel *BenzModel = (BenzModel *)malloc(sizeof(BenzModel));
    if(!BenzModel)
    {
        return NULL;
    }

    BenzModel.carModel.start      =  BenzStart;
    BenzModel.carModel.stop       =  BenzStop;
    BenzModel.carModel.alarm      =  BenzAlarm;
    BenzModel.carModel.engineBoom =  BenzEngineBoom;

    return BenzModel;
}

2.2.2 Builder抽象建造者

规范产品的组建,一般由子类实现,通过setSequence装配顺序就可以产生不同的产品。

/* 抽象建造者 */
typedef struct _CarlBuilder CarBuilder;
struct _CarlBuilder
{
    void (*setSequence)(unsigned char *pParam1, unsigned char *pParam2,
        unsigned char *pParam3, unsigned char *pParam4);
};

2.2.3 具体的建造者

实现抽象类中定义的所有方法,并且返回一个组建好的对象,实际用到的BenzBuilder和BmwBulder属于具体的建造者。

#include "Builder.h"

void DeleteBenzBuilder(BenzBuilder *pBenzBuilder)
{
    if(!pBenzBuilder->pBenzModel)
    {
        free(pBenzBuilder->pBenzModel);
        pBenzBuilder->pBenzModel = NULL;
        free(pBenzBuilder);
        pBenzBuilder = NULL;
    }
}


BenzBuilder *CreateBenzBuilder(void)
{

    BenzModel *pBenzModel = NULL;
    BenzBuilder *pBenzBuilder = (BenzBuilder *)malloc(sizeof(BenzBuilder));
    if(!pBenzBuilder)
    {
        return NULL;
    }
    
    memset(pBenzBuilder, 0, sizeof(BenzBuilder));
    pBenzModel  = CreateBenzModel();
    if(!pBenzModel)
    {
        return NULL;
    }

    pBenzBuilder->pBenzModel               = pBenzModel;
    pBenzBuilder->DeleteBenzBuilder        = DeleteBenzBuilder;
    pBenzBuilder->pCarBuilder.setSequence = setSequence;

    return pBenzBuilder;
}

2.2.4 Director导演类

负责安排已有模块的顺序,然后开始告诉Builder开始构建

BenzModel *getABenzModel(Director *pDirector)
{
    /*传递A类Benz车模行为顺序到benz车模建造者*/
    pDirector->pBenzBuilder->pCarBuilder.setSequence("engineBoom","start","alarm","stop");

    /*建造者按照要求组装出一个benz车模*/
    return pDirector->pBenzBuilder->pBenzModel;
}


BenzModel *getBBenzModel(Director *pDirector)
{
    /*传递B类Benz车模行为顺序到benz车模建造者*/
    pDirector->pBenzBuilder->pCarBuilder.setSequence("start","engineBoom","alarm","stop");
    /*建造者按照要求组装出一个benz车模*/
    return pDirector->pBenzBuilder->pBenzModel;
}

void DeleteDirector(Director *pDirector)
{
    if(!pDirector->pBenzBuilder)
    {
        pDirector->pBenzBuilder->DeleteBenzBuilder(pDirector->pBenzBuilder);
    }

    if(!pDirector->pBwnBuilder)
    {
        pDirector->pBwnBuilder->DeleteBmwBuilder(pDirector->pBwnBuilder);
    }

    free(pDirector);
    pDirector = NULL;
}


Director *CreateDirector(void)
{
    Director *pDirector = (Director *)malloc(sizeof(Director));
    if(!pDirector)
    {
        return NULL;
    }

    memset(pDirector, 0, sizeof(Director));
    pDirector->pBenzBuilder = CreateBenzBuilder();
    if(!pDirector->pBenzBuilder)
    {
        return NULL;
    }

    pDirector->pBwnBuilder  = CreateBmwBuilder();
    if(!pDirector->pBwnBuilder)
    {
        return NULL;
    }

    pDirector->getABenzModel  = getABenzModel;
    pDirector->getBBenzModel  = getBBenzModel;
    pDirector->DeleteDirector = DeleteDirector;

    return pDirector;
}

导演类起到封装的作用,避免高层模块深入到建造者内部的实现,当建造者比较庞大时,导演类可以有多个。

3 建造者模式的应用

3.1 建造者模式优点

  1. 封装性:使用建造者的客户端不必知道产品内部组成的细节,入例子中,我们就不需要关系每一个具体的模型内部是如何实现的,产生的对象就是CarModel
  2. 建造者独立,很容易扩展,增加新的具体建造者无需修改原有类库的代码,系统扩展比较方便,符合开闭原则。
  3. 便于控制细节风险,具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何的影响。

3.2 建造者模式缺点

  1. 对于所创建的产品有一定限制:一般这些产品都具有一些较多的共同点,其组成部分相似。如果差异性很大,那么则不适合使用建造者模式
  2. 如果产品的内部结构复杂多变,可能会需要定义很多具体构建者来实现这些变化,会导致系统变得庞大,增加系统的理解难度和运行成本

3.3 建造者模式使用场景

  1. 相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式
  2. 多个部件或者零件,都可以装配到一个对象中,但是产生的运行结果又不相同,则可以采用该模式
  3. 产品非常复杂,或者产品中调用顺序不同产生的不同的结果

3.4 建造者模式注意事项

建造者模式与抽象工厂模式有点相似,建造者模式关注的是零件类型和装配工艺(顺序),而抽象工厂模式则关注的是创建,创建零件是它的主要责任,组装则与它无关。如果将抽象工厂模式看成一个汽车配件生产厂,生成不同类型的汽车配件,那么建造者模式则是一个汽车组装厂,通过对配件进行组成返回一辆完整的汽车。

4 参考资料

秦晓波, 《设计模式之禅》

刘伟,《设计模式的艺术—软件开发人员内功修炼之道》

转载于:https://www.cnblogs.com/pingchangxin2018/p/9952594.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值