设计模式学习笔记--建造者模式

一.简介

建造者模式也是六个创建型设计模式之一,用于对象的创建过程。建造者模式的主要作用是将对象的构建和表示分离,使得同样的构建过程可以创建不同的具体对象。在创建一系列对象时,对象的创建过程大体相同,但是具体过程不同时,就可以使用创建者模式。比如我门画一个人的时候,都是需要画头,身体,胳膊和腿的,但是具体怎么画就大不相同了。建造者模式给出了一个创造时的模板,并且给出了创建对象的实际接口(或者是Director类)。我们要改变创建过程的时候,只需要覆写相关的具体创建过程函数,就可以改变创建的过程。
建造者模式的UML图如下:


二.建造者模式的具体实现


上个例子,例子中写的比较清楚:
// C++Test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;




//抽象的对象类,只提供具体创建方法的接口,不提供实现
class Builder
{
private:
	string m_partA;
	string m_partB;
	string m_partC;
public:
	virtual void BuildPartA() = 0;
	virtual void BuildPartB() = 0;
	virtual void BuildPartC() = 0;

	void SetPartA(string a){m_partA = a;}
	void SetPartB(string b){m_partB = b;}
	void SetPartC(string c){m_partC = c;}

	void Show()
	{
		cout<<m_partA<<" "<<m_partB<<" "<<m_partC<<endl;
	}

	Builder* GetResult()
	{
		return this;
	}
};


//具体的对象类,实现了具体的创建方法
class ConcreteBuilder : public Builder
{
	void BuildPartA() override;
	void BuildPartB() override;
	void BuildPartC() override;
};

void ConcreteBuilder::BuildPartA()
{
	SetPartA("Con1 partA");
}

void ConcreteBuilder::BuildPartB()
{
	SetPartB("Con1 partB");
}

void ConcreteBuilder::BuildPartC()
{
	SetPartC("Con1 partC");
}



//创建director,提供创建接口
class BuilderDirector
{
public:
	void Build(Builder* buider)
	{
		buider->BuildPartA();
		buider->BuildPartB();
		buider->BuildPartC();
	}
};


int _tmain(int argc, _TCHAR* argv[])
{
	//创建一个具体的Builder
	Builder* builder = new ConcreteBuilder();
	//创建builderdirector
	BuilderDirector* builderdir = new BuilderDirector();
	//通过builderdirector来控制创建
	builderdir->Build(builder);
	//获得结果(不用这一步也可以,经过build之后的builder本身就是已经创建好的对象了)
	Builder* result = builder->GetResult();
	
	result->Show();

	system("pause");
	return 0;
}
结果:
Con1 partA Con1 partB Con1 partC
请按任意键继续. . .

创建对象的时候,初始化操作并不应该放在构造函数中(可能有一些默认初值,比如指针置空的操作),真正的初始化应该是一个单独的Init操作。但是这个Init操作有时也是很复杂的,需要初始化各个子模块。如果对象的创建过程大致类似,仅仅是各个子模块的初始化有所差异,那么就将子模块的初始化放在派生类中进行具体的修改。创建的过程遵循一系列固定的流程,这就是建造者模式。
例子中,Builder基类仅仅给出了三个子模块创建的抽象接口,ConcreteBuilder继承了Builder,实现了具体创建的过程。通过Director类固定好的创建模式,多态调用具体的ConcreteBuilder实现了对象的创建。

三.建造者模式的使用条件

建造者模式主要是对于构建一个包含多个组件的对象,使用相同的构建过程构建不同种类的对象的一种设计模式。
在以下场景中适用建造者模式:


(1)对象由多个不同的组件构成。
(2) 对象的各个组件可能有相互依赖,可能还需要指定构建顺序。
(3) 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中。
(4) 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。

 适用建造者模式,我们可以不必了解对象内部细节,将对象的创建过程和对象本身解耦,让相同的创建过程可以创建不同的对象。并且,如果我们新增了一种对象,只需要给出具体的ConcreteBuilder即可,复合“开放封闭原则”。将创建过程分成各个部分,而不是单独的一个Init,可以让创建过程更加清晰。
但是使用建造者模式也限制了一些条件,要创建的对象必须有相同的结构,都覆写基类的具体创建过程,并且使用相同的创建顺序。


四.创建过程中的控制

上面说过,创建过程中有些限制条件,但是,如果我们想要更加灵活的进行创建,让某些创建过程工作,某些创建过程不工作的话,就可以通过一种叫做“钩子函数”的东东,进行控制。
看一个例子:
// C++Test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;




//抽象的对象类,只提供具体创建方法的接口,不提供实现
class Builder
{
private:
	string m_partA;
	string m_partB;
	string m_partC;
public:
	virtual void BuildPartA() = 0;
	virtual void BuildPartB() = 0;
	virtual void BuildPartC() = 0;

	void SetPartA(string a){m_partA = a;}
	void SetPartB(string b){m_partB = b;}
	void SetPartC(string c){m_partC = c;}

	//钩子函数,默认是返回true的,如果想控制其为false,只需要在派生类将其覆写即可
	virtual bool IsNeedPartA(){return true;}

	void Show()
	{
		cout<<m_partA<<" "<<m_partB<<" "<<m_partC<<endl;
	}

	Builder* GetResult()
	{
		return this;
	}
};


//具体的对象类,实现了具体的创建方法
class ConcreteBuilder : public Builder
{
	void BuildPartA() override;
	void BuildPartB() override;
	void BuildPartC() override;
};

void ConcreteBuilder::BuildPartA()
{
	SetPartA("Con1 partA");
}

void ConcreteBuilder::BuildPartB()
{
	SetPartB("Con1 partB");
}

void ConcreteBuilder::BuildPartC()
{
	SetPartC("Con1 partC");
}



//创建director,提供创建接口
class BuilderDirector
{
public:
	void Build(Builder* buider)
	{
		//此处使用函数进行判断,是否需要初始化partA
		if(buider->IsNeedPartA())
		{
			buider->BuildPartA();
		}
		buider->BuildPartB();
		buider->BuildPartC();
	}
};


int _tmain(int argc, _TCHAR* argv[])
{
	//创建一个具体的Builder
	Builder* builder = new ConcreteBuilder();
	//创建builderdirector
	BuilderDirector* builderdir = new BuilderDirector();
	//通过builderdirector来控制创建
	builderdir->Build(builder);
	//获得结果(不用这一步也可以,经过build之后的builder本身就是已经创建好的对象了)
	Builder* result = builder->GetResult();
	
	result->Show();

	system("pause");
	return 0;
}
结果:
Con1 partA Con1 partB Con1 partC
请按任意键继续. . .

默认情况钩子函数返回的是true,如果我们想要不初始化A部分,那么就在Concrete类中将钩子函数覆写,返回false,这样,BuilderDirector中就会在判断的时候,去除PartA的创建。
我们在ConCreteBuilder中覆写IsNeedPartA函数:
<span style="white-space:pre">	</span>bool IsNeedPartA() override
	{
		return false;
	}



结果:
 Con1 partB Con1 partC
请按任意键继续. . .

可见PratA在钩子函数为false的情况下没有被构建。


五.简化版本的建造者模式

类似工厂模式那样,创建对象可以使用一个static方法而省略具体的工厂。建造者模式也可以将Director省略,直接将创建过程放在Builder类中。
// C++Test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;




//抽象的对象类,只提供具体创建方法的接口,不提供实现
class Builder
{
private:
	string m_partA;
	string m_partB;
	string m_partC;
public:
	virtual void BuildPartA() = 0;
	virtual void BuildPartB() = 0;
	virtual void BuildPartC() = 0;

	void SetPartA(string a){m_partA = a;}
	void SetPartB(string b){m_partB = b;}
	void SetPartC(string c){m_partC = c;}

	void Show()
	{
		cout<<m_partA<<" "<<m_partB<<" "<<m_partC<<endl;
	}

	Builder* GetResult()
	{
		return this;
	}

	//将Director的内容合并到抽象类中
	static void CreateBuilder(Builder* builder);
};

void Builder::CreateBuilder(Builder* builder)
{
	builder->BuildPartA();
	builder->BuildPartB();
	builder->BuildPartC();
}


//具体的对象类,实现了具体的创建方法
class ConcreteBuilder : public Builder
{
	void BuildPartA() override;
	void BuildPartB() override;
	void BuildPartC() override;

};

void ConcreteBuilder::BuildPartA()
{
	SetPartA("Con1 partA");
}

void ConcreteBuilder::BuildPartB()
{
	SetPartB("Con1 partB");
}

void ConcreteBuilder::BuildPartC()
{
	SetPartC("Con1 partC");
}





int _tmain(int argc, _TCHAR* argv[])
{
	//创建一个具体的Builder
	Builder* builder = new ConcreteBuilder();
	//通过Builder自带的static方法,构建builder
	Builder::CreateBuilder(builder);
	//获得结果(不用这一步也可以,经过build之后的builder本身就是已经创建好的对象了)
	Builder* result = builder->GetResult();
	
	result->Show();

	system("pause");
	return 0;
}
结果:
Con1 partA Con1 partB Con1 partC
请按任意键继续. . .

这里,由于Builder通常为抽象类,不能直接实例化,所以采用的是将具体Builer的指针作为参数传递给CreateBuilder方法,在该方法中调用一系列初始化的函数完成对象的创建。该方法不需要对象对应就可以使用,故采用了static方法。




最后附上一篇大牛的博客链接:








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值