跳转至

建造者模式

造房子

建造一个房子的过程很复杂,要有天花板地板门窗。需要把建造的过程分离出来。

建房子的人可以建楼房,建别墅,建平房。

适用于一个对象的构建比较复杂,将一个对象的构建和对象的表示进行分离。

房子抽象一个类,建造房子(工程队)抽象一个类。建造房子需要组合需要一个指挥者设计着。

对象的构建:

造门 造墙 造地面。

把建造的过程单独的写一个类。因为它太复杂了。于是就出现了工程队。

工程队里面去造门造墙造地板。

为什么要把工程队进行抽象:

客户可以选择工程队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个属性,可以将它分为四组。

  1. 个人信息
  2. 联系方式
  3. 地址信息
  4. 公司信息

我们把Person类根据职责分割成了几个不同的类。我们创建了多个建造者,他们分别管理相关分组内的属性,而Person只持有这些建造者。

我们拥有一个建造者基类PersonBuilder和四个衍生的建造者类,

PersonPersonalDetailsBuilder, PersonContactDetailsBuilder, PersonAddressDetailsBuilder和 PersonCompanyDetailsBuilder。

当其他四个从Personbuilder衍生出来的建造者需要更新相关属性时,Personbuilder这个基类可以帮助我们在它们之间进行转换。

在这个例子中我们可以看到新的构造方法变得更加易读了,我们可以用一种更加优雅的方式更新一组或者某一个属性。

需要注意一下,上面的例子中我们再每个建造者更新方法之后返回了它自己。这让我们能够在相同的建造者中写出链式方法,而不是分开的多行。这个概念称为流程模式。

优点

  1. 用一种优雅的方式很容易地初始化一个含很多参数的类。
  2. 遵从单一职责原则。
  3. 根据情况,以任意的顺序初始化对象和更新属性。
//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).")
}