设计模式-建造者模式C++

一、定义

将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式的基本思想是使用简单对象一步步构建一个复杂的对象。属于创建型模式。

建造者模式更关注各对象的组装过程,实现各个部件相互独立,并组装为复杂整体的作用。

二、建造者模式实例

每逢中秋,各商家都会生产出带有各种包装,用于各种场合的月饼产品。因为月饼产品除了月饼不可或缺外,由于使用场景不同,客户可能对产品的包装有不同的需求,这就导致“构建”月饼产品十分的复杂。

我们以“构建”这样的月饼产品为例。首先,我们假设我们的产品可能需要下列部件:

月饼(需要明确口味)、内包装、外包装、礼品袋。即具有这些成员的月饼类

class Mooncake
{
    string _filling;           //月饼口味
	string _innerPackaging;	   //内包装
	string _outerPackaging;    //外包装
	string _giftBags;          //礼品袋包装
}

对于目标:构建出一件月饼产品,我们有如下方法

1、折叠式构造方法

定义一批构造函数,覆盖对必选和可选部件的组合,在构造时确认组装产品的部件

//折叠式构造方式
class Mooncake
{
public:
	Mooncake(string filling) : _filling(filling) {}
	Mooncake(string filling, string innerPackaging) : _filling(filling), _innerPackaging(innerPackaging) {}
	Mooncake(string filling, string innerPackaging, string outerPackaging) : _filling(filling), _innerPackaging(innerPackaging), _outerPackaging(outerPackaging) {}
	Mooncake(string filling, string innerPackaging, string outerPackaging, string giftBags) : _filling(filling), _innerPackaging(innerPackaging), _outerPackaging(outerPackaging), _giftBags(giftBags) {}
	//...这还不止,还需要其他组合。例如_filling + _outerPackaging的。以下都省略
private:
	string _filling;           //月饼口味(必选)
	string _innerPackaging;	   //内包装
	string _outerPackaging;    //外包装
	string _giftBags;          //礼品袋包装
};

int main()
{
    //内包装为纸盒的五仁馅月饼产品
    Mooncake *moonCake = new Mooncake("五仁",“纸盒”);
}

2、对外暴露部件设置,使各部件可以构造后再设置

class Mooncake
{
public:
	Mooncake() :
		_filling(""),
		_innerPackaging(""),
		_outerPackaging(""),
		_giftBags("") {}

	virtual ~Mooncake() {}

	//內馅在子类实现确认
	void SetFilling(string param)
	{
		_filling = param;
	}

	void SetInnerPackaging(string param)
	{
		_innerPackaging = param;
	}

	void SetOuterPackaging(string param)
	{
		_outerPackaging = param;
	}

	void SetGiftBags(string param)
	{
		_giftBags = param;
	}

protected:
	string _filling;           //月饼口味
	string _innerPackaging;	   //内包装
	string _outerPackaging;    //外包装
	string _giftBags;          //礼品袋包装
};

int main()
{
    Mooncake *moonCake = new Mooncake();
    moonCake -> SetFilling("五仁");
    moonCake -> SetOuterPackaging("一次性方便袋");
}

但是上述2都有些显然的缺点。

使用方法1的构造函数要时刻注意传参的顺序是否错误,因为一旦传参太多,容易造成混乱,对可读性也不是很友好。而且一旦构建的可能组合太多,会需要大量构造函数。

使用方法2,虽然可以很方便地传入正确参数,将“部件”设置正确,也足够灵活。但是对象中的属性是分步设置的,在没有构建完成时,产品对象就已经对外暴露了,容易发生错误。

对于以上需求,我们可以用建造者模式解决。

3、建造者模式的实现

1)月饼产品类,提供对外设置属性的接口,但是和2方法不同

class Mooncake
{
public:
	Mooncake() :
		_filling(""),
		_innerPackaging(""),
		_outerPackaging(""),
		_giftBags("") {}

	virtual ~Mooncake() {}

	//內馅在子类实现确认
	void SetFilling(string param)
	{
		_filling = param;
	}

	void SetInnerPackaging(string param)
	{
		_innerPackaging = param;
	}

	void SetOuterPackaging(string param)
	{
		_outerPackaging = param;
	}

	void SetGiftBags(string param)
	{
		_giftBags = param;
	}

	void Introduce()
	{
		cout << "这款月饼是" << _filling << "馅的" << endl;
		if ("" != _innerPackaging)
		{
			cout << "内包装采用" << _innerPackaging << endl;
		}
		else
		{
			cout << "无内包装" << endl;
		}

		if ("" != _outerPackaging)
		{
			cout << "外包装采用" << _outerPackaging << endl;
		}
		else
		{
			cout << "无外包装" << endl;
		}

		if ("" != _giftBags)
		{
			cout << "具有" << _giftBags << "的礼品袋" << endl;
		}

		cout << "您看是否符合您的需求。" << endl;
	}
protected:
	string _filling;           //月饼口味
	string _innerPackaging;	   //内包装
	string _outerPackaging;    //外包装
	string _giftBags;          //礼品袋包装
};

2)构建者抽象类,声明构建月饼产品的接口,用于规范化产品的构建,一般由子类具体实现构建方法

class Builder
{
public:
	virtual ~Builder() {}

	virtual void buildFilling() = 0;                     //构建內馅

	virtual void buildInnerPackaging(string param) = 0;  //构建内包装

	virtual void buildOuterPackaging(string param) = 0;  //构建外包装

	virtual void buildGiftBags(string param) = 0;        //构建礼品袋

	virtual Mooncake* build() = 0;                               //对外提供构建的对象的指针
protected:
	Mooncake *_moonCake;              //待构建的对象指针
};

3)构建者具体类-五仁月饼构建者(filling属性可以确认),可以具体实现对目标对象的构建

class FiveNutsMooncakeBuilder :public Builder
{
public:
	FiveNutsMooncakeBuilder()
	{
		_moonCake = new Mooncake();
	}

	~FiveNutsMooncakeBuilder()
	{
		if (nullptr != _moonCake)
		{
			delete _moonCake;
			_moonCake = nullptr;
		}
	}
	void buildFilling()
	{
		if (nullptr != _moonCake)
		{
			_moonCake->SetFilling("五仁");
		}
	}

	void buildInnerPackaging(string param)
	{
		if (nullptr != _moonCake)
		{
			_moonCake->SetInnerPackaging(param);
		}
	}

	void buildOuterPackaging(string param)
	{
		if (nullptr != _moonCake)
		{
			_moonCake->SetOuterPackaging(param);
		}
	}

	void buildGiftBags(string param)
	{
		if (nullptr != _moonCake)
		{
			_moonCake->SetGiftBags(param);
		}
	}

    Mooncake* build()
	{
		return _moonCake;
	}
};

4)指挥者类,传入构建者对象,指挥构建者对产品的构建过程。在这个案例中,我写了两种组建方案:简单包装和精美包装。虽然里面的月饼可能是相同的产品,但是大家都知道这肯定是2种价格~

class Director
{
public:
	Director(Builder* bd) :_builder(bd) {}
	~Director()
	{
		if (nullptr != _builder)
		{
			delete _builder;
			_builder = nullptr;
		}
	}

	//简单包装的月饼产品
	Mooncake* SimplePackaging()
	{
		if (nullptr != _builder)
		{
			_builder->buildFilling();
			_builder->buildOuterPackaging("纸盒");
			return _builder->build();
		}
	}

	//精美包装的月饼产品
	Mooncake* GiftPackaging()
	{
		if (nullptr != _builder)
		{
			_builder->buildFilling();
			_builder->buildInnerPackaging("纸盒");
			_builder->buildOuterPackaging("精美铁盒");
			_builder->buildGiftBags("礼品袋");
			return _builder->build();
		}
	}

private:
	Builder* _builder;
};

5)使用

int main(int argc, char *argv[])
{
	Builder *builder = new FiveNutsMooncakeBuilder();
	Director *direstor = new Director(builder);
	cout << "顾客A:" << endl;
	//获取已经“建造”好的月饼产品
	Mooncake* moonCakeA = direstor->GiftPackaging();
	//输出介绍话术
	moonCakeA->Introduce();
	
	system("pause");
	return 0;
}

6)这样构建的产品对象,方便扩展。假如想要增加别的月饼产品,比如增加什锦月饼。则我们就可以新增一个构建者。

class MixedMooncakeBuilder :public Builder
{
public:
	MixedMooncakeBuilder()
	{
		_moonCake = new Mooncake();
	}

	~MixedMooncakeBuilder()
	{
		if (nullptr != _moonCake)
		{
			delete _moonCake;
			_moonCake = nullptr;
		}
	}
	void buildFilling()
	{
		if (nullptr != _moonCake)
		{
			_moonCake->SetFilling("什锦");
		}
	}

	void buildInnerPackaging(string param)
	{
		if (nullptr != _moonCake)
		{
			_moonCake->SetInnerPackaging(param);
		}
	}

	void buildOuterPackaging(string param)
	{
		if (nullptr != _moonCake)
		{
			_moonCake->SetOuterPackaging(param);
		}
	}

	void buildGiftBags(string param)
	{
		if (nullptr != _moonCake)
		{
			_moonCake->SetGiftBags(param);
		}
	}

	Mooncake* build()
	{
		return _moonCake;
	}
};

三、总结

1、优缺点

该模式的主要优点如下:

1)封装性好,构建和表示分离;

2)扩展性好,各个具体的建造者相互独立,有利于系统的解耦;

3)客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响,便于控制细节风险。


其缺点如下:

1)产品的组成部分必须相同,这限制了其使用范围。

2)如果产品的内部变化复杂,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。

2、建造者模式的适用场景

1、需要构建的对象相对复杂,具有多个属性,并且有些属性具有默认值;

2、相同的方法,不同的执行顺序,产生不同的结果;

3、多个部件,可以装配到一个对象中,但是不同组合产生的结果又不相同;

        创建的产品具备复杂创建过程时,可以抽取出共性创建过程,然后交由指挥者类自定义创建流程,使得同样的创建行为可以(传入不同构建者)生产出不同的产品,分离了创建与表示,使创建产品的灵活性大大增加。

【参考&致谢】

设计模式之建造者(Builder)模式 | 菜鸟教程 (runoob.com)https://www.runoob.com/w3cnote/builder-pattern.html建造者模式(Bulider模式)详解 (biancheng.net)http://c.biancheng.net/view/1354.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值