建造者模式¶
造房子¶
建造一个房子的过程很复杂,要有天花板地板门窗。需要把建造的过程分离出来。
建房子的人可以建楼房,建别墅,建平房。
适用于一个对象的构建比较复杂,将一个对象的构建和对象的表示进行分离。
房子抽象一个类,建造房子(工程队)抽象一个类。建造房子需要组合需要一个指挥者设计着。
对象的构建:¶
造门 造墙 造地面。
把建造的过程单独的写一个类。因为它太复杂了。于是就出现了工程队。
工程队里面去造门造墙造地板。
为什么要把工程队进行抽象:¶
客户可以选择工程队A,可以选择工程队B。
有的工程队擅长建楼房,有的工程队擅长建别墅。
一个产品由A,B,C,D,几部分组成。工程队内部建造A建造B建造C建造D。
对象的表示:¶
就是一个一个的产品(房子)
类和角色有下面4个:¶
-
Product产品 房子: ( 产品的表示)
-
窗户
- 地板
-
墙
-
Builder抽象工程队: 造不同的房子 (产品的构建)
造房子,要有一个方法得到一个房子
有一个造房子的函数。
-
ConcreteBuilde具体工程队 具体的创建产品的各个部分。
-
造别墅
- 造大楼
-
造平房
-
Director设计师:更专业一点的,客户需要设计师角色。
设计师设计蓝图, 里面调用工程队生产窗户,门,床,地板等。
指挥不同的工程队去干活。 设计师有带参数的构造函数 参数是工程队。
类和角色:客户端,设计师,工程队,产品
工程队和设计师解耦合。 对客户端使用者比较简单。而且可以创建各种各样的工程队造各种各样的房子。
因为造房子复杂 ,所以使用工程队建造房子的各个部分,设计师负责业务逻辑(调用工程队去构造房子的窗户,门,地板等)指挥工程队干货。
因为建房子的过程太复杂了,所以需要一个工程队来建造。工程队里面建A建B建C,工程队也有各种工程队。
如果只有工程队,一个工程队只能造一种房子,所以需要设计师,就能建不同的房子。把工程队进行抽象。
客户直接造房子不好,工程队直接写死了也不好,所以需要这种模式方法。
设计师Director写死了 没有分三六九等,所以设计者也可以抽象。然后就可以
扩展。房子也可以分很多类,所以产品房子也可以再抽象。然后一个复杂的系统就构建出来了。
请三六九等的设计师指挥三六九等的工程队造三六九等的房子。
#include <iostream>
using namespace std;
#include "string"
class House
{
public:
void setDoor(string door)
{
this->m_door = door;
}
void setWall(string wall)
{
this->m_wall = wall;
}
void setWindow(string window)
{
this->m_window = window;
}
//--
string getDoor( )
{
cout << m_door << endl;
return this->m_door ;
}
string getWall()
{
cout << m_wall << endl;
return this->m_wall;
}
string getWindow()
{
cout << m_window << endl;
return m_window;
}
private:
string m_door;
string m_wall;
string m_window;
};
class Builder
{
public:
virtual void buildWall() = 0;
virtual void buildDoor() = 0;
virtual void buildWindow() = 0;
virtual House* getHouse() = 0;
};
//公寓工程队
class FlatBuilder : public Builder
{
public:
FlatBuilder()
{
m_house = new House;
}
virtual void buildWall()
{
m_house->setWall(" flat wall");
}
virtual void buildDoor()
{
m_house->setDoor("flat door");
}
virtual void buildWindow()
{
m_house->setWindow("flat window");
}
virtual House* getHouse()
{
return m_house;
}
private:
House *m_house;
};
//别墅 villa 工程队
class VillaBuilder : public Builder
{
public:
VillaBuilder()
{
m_house = new House;
}
virtual void buildWall()
{
m_house->setWall(" villa wall");
}
virtual void buildDoor()
{
m_house->setDoor("villa door");
}
virtual void buildWindow()
{
m_house->setWindow("villa window");
}
virtual House* getHouse()
{
return m_house;
}
private:
House *m_house;
};
//设计师(指挥者) 负责建造逻辑
//建筑队 干具体的活
class Director
{
public:
Director( Builder * build)
{
m_build = build;
}
void Construct()
{
m_build->buildWall();
m_build->buildWindow();
m_build->buildDoor();
}
private:
Builder * m_build;
};
void main()
{
House *house = NULL;
Builder *builder = NULL;
Director *director = NULL;
// 请一个建造别墅的工程队
builder = new VillaBuilder;
//设计师 指挥 工程队 干活
director = new Director(builder);
director->Construct();
house = builder->getHouse();
house->getWindow();
house->getDoor();
delete house;
delete builder;
//请 FlatBuilder 公寓
builder = new FlatBuilder;
director = new Director(builder);
director->Construct();
house = builder->getHouse();
house->getWindow();
house->getDoor();
delete house;
delete builder;
delete director;
system("pause");
return ;
}
总结¶
建造者模式¶
创建一个房子类¶
- 数据成员
- 门
- 窗
- 墙
- 成员函数
- 门的setter和getter方法
- 窗的setter和getter方法
- 墙的setter和getter方法
工程队类¶
定义三个成员函数
- 门的setter方法
- 窗的setter方法
- 墙的setter方法
获取房子对象
具体的工程队对象¶
创建具体的工程队对象(别墅工程队,写字楼工程队,居民楼工程队),构造函数中 创造一个房子对象。
实现工程队类的三个成员函数,创造门,窗,墙。
获取一个房子。
设计师¶
指挥工程队去创造门,窗,墙。客户不用再调用工程队去创造门,窗,墙。省略步骤,更加简便。
个人信息¶
有一个Person类,它含有14个属性。这14个属性,可以将它分为四组。
- 个人信息
- 联系方式
- 地址信息
- 公司信息
我们把Person类根据职责分割成了几个不同的类。我们创建了多个建造者,他们分别管理相关分组内的属性,而Person只持有这些建造者。
我们拥有一个建造者基类PersonBuilder和四个衍生的建造者类,
PersonPersonalDetailsBuilder, PersonContactDetailsBuilder, PersonAddressDetailsBuilder和 PersonCompanyDetailsBuilder。
当其他四个从Personbuilder衍生出来的建造者需要更新相关属性时,Personbuilder这个基类可以帮助我们在它们之间进行转换。
在这个例子中我们可以看到新的构造方法变得更加易读了,我们可以用一种更加优雅的方式更新一组或者某一个属性。
需要注意一下,上面的例子中我们再每个建造者更新方法之后返回了它自己。这让我们能够在相同的建造者中写出链式方法,而不是分开的多行。这个概念称为流程模式。
优点
- 用一种优雅的方式很容易地初始化一个含很多参数的类。
- 遵从单一职责原则。
- 根据情况,以任意的顺序初始化对象和更新属性。
//Person class which only contains the details
class Person {
//personal details
var name: String = ""
var gender: String = ""
var birthDate: String = ""
var birthPlace: String = ""
var height: String = ""
var weight: String = ""
//contact details
var phone: String = ""
var email: String = ""
//address details
var streeAddress: String = ""
var zipCode: String = ""
var city: String = ""
//work details
var companyName: String = ""
var designation: String = ""
var annualIncome: String = ""
//empty constructor
init() { }
}
//PersonBuilder class helps to construct the person class instance
class PersonBuilder {
var person: Person
init(person: Person){
self.person = person
}
//personal details builder switching
var personalInfo: PersonPersonalDetailsBuilder {
return PersonPersonalDetailsBuilder(person: self.person)
}
//contact details builder switching
var contacts: PersonContactDetailsBuilder {
return PersonContactDetailsBuilder(person: self.person)
}
//address details builder switching
var lives: PersonAddressDetailsBuilder {
return PersonAddressDetailsBuilder(person: self.person)
}
//work details builder switching
var works: PersonCompanyDetailsBuilder {
return PersonCompanyDetailsBuilder(person: self.person)
}
func build() -> Person {
return self.person
}
}
//PersonPersonalDetailsBuilder: update personal details
class PersonPersonalDetailsBuilder: PersonBuilder {
func nameIs(_ name: String) -> Self {
self.person.name = name
return self
}
func genderIs(_ gender: String) -> Self {
self.person.gender = gender
return self
}
func bornOn(_ birthDate: String) -> Self {
self.person.birthDate = birthDate
return self
}
func bornAt(_ birthPlace: String) -> Self {
self.person.birthPlace = birthPlace
return self
}
func havingHeight(_ height: String) -> Self {
self.person.height = height
return self
}
func havingWeight(_ weight: String) -> Self {
self.person.weight = weight
return self
}
}
//PersonContactDetailsBuilder: update contact details
class PersonContactDetailsBuilder: PersonBuilder {
func hasPhone(_ phone: String) -> Self {
self.person.phone = phone
return self
}
func hasEmail(_ email: String) -> Self {
self.person.email = email
return self
}
}
//PersonAddressDetailsBuilder: update address details
class PersonAddressDetailsBuilder: PersonBuilder {
func at(_ streeAddress: String) -> Self {
self.person.streeAddress = streeAddress
return self
}
func withZipCode(_ zipCode: String) -> Self {
self.person.zipCode = zipCode
return self
}
func inCity(_ city: String) -> Self {
self.person.city = city
return self
}
}
//PersonCompanyDetailsBuilder: update company details
class PersonCompanyDetailsBuilder: PersonBuilder {
func inCompany(_ companyName: String) -> Self {
self.person.companyName = companyName
return self
}
func asA(_ designation: String) -> Self {
self.person.designation = designation
return self
}
func hasAnnualEarning(_ annualIncome: String) -> Self {
self.person.annualIncome = annualIncome
return self
}
}
func testBuilder() {
var person = Person() //person with empty details
let personBuilder = PersonBuilder(person: person)
person = personBuilder
.personalInfo //个人信息
.nameIs("Hitendra Solanki")
.genderIs("Male")
.bornOn("2nd Oct 1991")
.bornAt("Gujarat, India")
.havingHeight("5.9 ft")
.havingWeight("85 kg")
.contacts //联系方式
.hasPhone("+91 90333-71772")
.hasEmail("hitendra.developer@gmail.com")
.lives //住址
.at("52nd Godrej Street")
.inCity("Ahmedabad")
.withZipCode("380015")
.build()
//use of Person object
print("\(person.name) has contact number \(person.phone) and email \(person.email)")
//later on when we have company details ready for the person
person = personBuilder
.works //工作
.asA("Software architect")
.inCompany("Fortune 500")
.hasAnnualEarning("45,000 USD")
.build()
//use of Person object with update info
print("\(person.name) works in \(person.companyName) compay as a \(person.designation).")
}