建造者模式

1、建造者模式的概念

 原文链接:https://blog.csdn.net/h8062651/article/details/136311165

 建造者模式(Builder Pattern)是一种创建型设计模式,也被称为生成器模式。它的核心思想是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

在建造者模式中,通常包括以下几个角色:

(1)Builder: 这是一个抽象接口,定义了产品对象的各个组成成分的建造。它规定了要实现复杂对象的哪些部分的创建,但并不涉及具体的对象部件的创建。
(2)ConcreteBuilder: 这是实现了Builder接口的具体类,它针对不同的商业逻辑,具体化了复杂对象的各部分的创建。在建造过程完成后,它提供产品的实例。
(3)Director: 这是一个指挥者角色,它调用具体建造者来创建复杂对象的各个部分。在指导者中,不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
(4)Product: 这是最终要创建的复杂对象。

建造者模式允许用户只通过指定复杂对象的类型和内容来构建对象,而不需要知道内部的具体构建细节。这种模式特别适用于构建具有多个组成部分的复杂对象,且这些组成部分的构建过程可能会因具体需求而有所不同的情况。通过建造者模式,可以使得同样的构建过程能够创建出不同的产品表示,提高了系统的灵活性和可扩展性。

1.1 建造者模式的应用场景

(1.1.1)场景需求

墨菲定律中提到:任何事都没有表面看起来的那么简单。无论在现实生活中还是在代码世界中,都存在一些复杂的对象,他们由多个部分组成,每个部分各具功能,协同运作。比如手机包含摄像头、CPU、电池等各种零部件。对于大部分用户而言,无须知道部件之间的组装细节,也几乎不会单独使用某个零部件,而是使用一部完整的手机。如果需要详细关注一个产品部件的生产、安装步骤,可以选择建造者模式对其进行设计与描述,将部件和其组装过程分开,分步创建一个复杂的对象。由于组装部件的过程复杂,因此,装配过程被分离到一个称作建造者的对象里,建造者返回给上层一个完整产品,而无须关心该产品的构建细节,这就是建造者模式的核心思想。

(1.1.2)建造者模式通常适用于以下应用场景:

(1)对象结构复杂: 当需要创建的对象具有复杂的内部结构,包含多个组件或属性时,可以使用建造者模式来构建这些对象。通过将构建过程分解为多个步骤,可以更加清晰地管理和控制对象的创建过程。
(2)创建流程固定: 当对象的创建流程是固定的,即无论创建多少个对象,其构建步骤都是相同的时候,可以使用建造者模式。通过将这些步骤封装在建造者类中,可以确保每次创建对象时都遵循相同的流程。
(3)需要控制创建过程: 当需要更加灵活地控制对象的创建过程,例如根据用户输入或运行时条件来决定对象的某些属性时,可以使用建造者模式。通过在指挥者类中引入逻辑来控制对象的创建,可以实现更加灵活的构建过程。
(4)代码易于阅读和维护: 当需要创建的对象具有大量的参数或配置选项时,使用建造者模式可以将这些参数和选项分组并封装在不同的建造者类中,从而减少构造函数的复杂度,使代码更加易读和易于维护。

在实际应用中,建造者模式常用于构建具有多个组件或属性的复杂对象,如UI界面、配置文件、数据库查询结果等。通过使用建造者模式,可以更加清晰地组织代码,提高代码的可读性和可维护性,同时降低对象创建的复杂性。

1.2 建造者模式的优点和缺点   

  建造者模式的优点主要包括:

(1)封装性好: 建造者模式将对象的构建与它的表示分离,使得客户端不必知道产品内部组成的细节,隐藏了产品的内部实现细节,提供了更好的封装性。
(2)扩展性好: 由于具体的建造者是相互独立的,因此易于扩展。如果需要增加新的部件或修改现有部件的创建方式,只需要增加或修改相应的建造者类,而不会影响其他已构建的部件和客户端代码。
(3)控制细节风险: 建造者模式允许对创建过程逐步细化,而不对其他模块产生任何影响,便于控制细节风险。客户端只需要指定需要构建的对象类型和内容,而不需要了解具体的构建细节,从而降低了客户端代码的复杂性。

然而,建造者模式也存在一些缺点:

(1)使用范围受限: 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似。如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制。
(2)可能导致系统庞大: 如果产品的内部变化复杂,可能需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。这会增加系统的理解难度和运行成本,因为需要维护大量的建造者类。

综上所述,建造者模式在创建具有复杂内部结构和多个组件的对象时非常有用,可以提供良好的封装性、扩展性和对细节的控制。然而,它也有一些限制,特别是在产品差异性大或内部变化复杂的情况下。因此,在使用建造者模式时需要权衡其优点和缺点,并根据具体的应用场景做出决策。

2、建造者模式的实现步骤

   本章节使用一个建造房子的样例来讲解建造者模式的实现步骤。

2.1 定义产品(Product)类

首先,定义 Product 类,它表示最终要构建的对象。在本章节的例子中,构建一个 House 类:

#include <iostream>  
#include <memory>  
#include <string>  

class House 
{
public:
    void setWalls(const std::string& walls) 
    {
        this->walls = walls;
    }

    void setRoof(const std::string& roof) 
    {
        this->roof = roof;
    }

    void setFloors(const std::string& floors) 
    {
        this->floors = floors;
    }

    void showHouseDetails() const 
    {
        std::cout << "Walls: " << walls << std::endl;
        std::cout << "Roof: " << roof << std::endl;
        std::cout << "Floors: " << floors << std::endl;
    }

private:
    std::string walls;
    std::string roof;
    std::string floors;
};


2.2 定义抽象建造者(Builder)接口

接下来,定义一个 Builder 抽象接口,它声明了构建 House 对象所需的方法:

class HouseBuilder 
{
public:
    virtual ~HouseBuilder() = default;

    virtual void buildWalls() = 0;
    virtual void buildRoof() = 0;
    virtual void buildFloors() = 0;

    virtual std::shared_ptr<House> getHouse() = 0;  
};  


2.3 定义具体建造者(ConcreteBuilder)类

然后,创建实现 HouseBuilder 接口的 ConcreteBuilder 类。这个类将包含构建 House 对象所需的具体实现:

class ConcreteHouseBuilder : public HouseBuilder 
{
public:
    ConcreteHouseBuilder() : house(std::make_shared<House>()) {}

    void buildWalls() override 
    {
        house->setWalls("Concrete walls");
    }

    void buildRoof() override 
    {
        house->setRoof("Concrete roof");
    }

    void buildFloors() override 
    {
        house->setFloors("Concrete floors");
    }

    std::shared_ptr<House> getHouse() override
    {
        return std::move(house);
    }

private:
    std::shared_ptr<House> house;
};


2.4 定义指挥者(Director)类

接下来,创建一个 Director 类,它负责指挥 Builder 对象来构建 Product 对象:

class HouseDirector 
{
public:
    HouseDirector(std::shared_ptr<HouseBuilder> builder) : builder(builder) {}

    void constructHouse() 
    {
        builder->buildWalls();
        builder->buildRoof();
        builder->buildFloors();
    }

    std::shared_ptr<House> getHouse()
    {
        return builder->getHouse();
    }

private:
    std::shared_ptr<HouseBuilder> builder;

};

2.5 客户端使用

最后,在 main 函数中,使用这些类来构建 House 对象:

int main() 
{
    // 创建具体建造者对象  
    auto builder = std::make_shared<ConcreteHouseBuilder>();

    // 创建指挥者对象,并将建造者传递给指挥者  
    HouseDirector director(builder);

    // 通过指挥者构建产品  
    director.constructHouse();

    // 获取并显示构建好的产品  
    auto house = director.getHouse();
    house->showHouseDetails();

    return 0;
}


上面代码的输出为:

Walls: Concrete walls
Roof: Concrete roof
Floors: Concrete floors

在上面代码中,使用 std::make_shared 来创建 ConcreteHouseBuilder 对象,并将其传递给 HouseDirector 。HouseDirector 通过调用 concreteHouseBuilder 的方法逐步构建了一个 House 对象,并通过 getHouse 方法返回了 House 对象的所有权。最后,获取这个构建好的 House 对象,并显示其对象细节。

3、建造者模式的案例解析

3.1 对象结构复杂场景下使用建造者模式

如下的样例将展示如何使用建造者模式来构建一个 Computer 对象,其中包含 Processor 和 Memory 两个子组件(为了简化代码,实际一个电脑的子组件会很多)。

首先,定义各个子组件以及 Computer 类:

#include <iostream>  
#include <memory>  
#include <string>  

// 子组件类  
class Processor 
{
public:
    void setSpeed(int speed) { m_speed = speed; }
    void setCores(int cores) { m_cores = cores; }

    void showDetails() const {
        std::cout << "Processor: " << m_speed << " MHz, " << m_cores << " cores" << std::endl;
    }

private:
    int m_speed;
    int m_cores;
};

class Memory 
{
public:
    void setSize(int size) { m_size = size; }
    void setType(const std::string& type) { m_type = type; }

    void showDetails() const {
        std::cout << "Memory: " << m_size << " GB, " << m_type << " RAM" << std::endl;
    }

private:
    int m_size;
    std::string m_type;
};


// 产品类  
class Computer {
public:
    void setProcessor(std::shared_ptr<Processor> processor) { m_processor = processor; }
    void setMemory(std::shared_ptr<Memory> memory) { m_memory = memory; }

    void showDetails() const {
        m_processor->showDetails();
        m_memory->showDetails();
    }

private:
    std::shared_ptr<Processor> m_processor;
    std::shared_ptr<Memory> m_memory;
};
接下来,定义抽象建造者接口和具体的建造者类:

// 抽象建造者接口  
class ComputerBuilder 
{
public:
    virtual ~ComputerBuilder() = default;

    virtual void buildProcessor() = 0;
    virtual void buildMemory() = 0;

    virtual std::shared_ptr<Computer> getComputer() = 0;
};

// 具体建造者类  
class GamingComputerBuilder : public ComputerBuilder 
{
public:
    GamingComputerBuilder() : m_computer(std::make_shared<Computer>()) {
        m_processor = std::make_shared<Processor>();
        m_memory = std::make_shared<Memory>();
    }

    void buildProcessor() override {
        m_processor->setSpeed(3500);
        m_processor->setCores(6);
    }

    void buildMemory() override {
        m_memory->setSize(16);
        m_memory->setType("DDR4");
    }

    std::shared_ptr<Computer> getComputer() override {
        m_computer->setProcessor(m_processor);
        m_computer->setMemory(m_memory);
        return m_computer;
    }

private:
    std::shared_ptr<Computer> m_computer;
    std::shared_ptr<Processor> m_processor;
    std::shared_ptr<Memory> m_memory;
};
然后,定义 Director 类,负责指导 Builder 对象如何构建最终的产品:

class Director 
{
public:
    Director(std::shared_ptr<ComputerBuilder> builder) : m_builder(builder) {}

    void constructComputer() {
        m_builder->buildProcessor();
        m_builder->buildMemory();
    }

    std::shared_ptr<Computer> getComputer() {
        return m_builder->getComputer();
    }

private:
    std::shared_ptr<ComputerBuilder> m_builder;
};


最后,在 main 函数中使用 Director 和 GamingComputerBuilder 来构建一个 Computer 对象:
上面代码的输出为:

int main() 
{
    // 创建具体的建造者对象  
    std::shared_ptr<ComputerBuilder> builder = std::make_shared<GamingComputerBuilder>();

    // 创建导演对象,并将建造者对象传递给它  
    Director director(builder);

    // 指导构建过程  
    director.constructComputer();

    // 获取构建好的产品  
    std::shared_ptr<Computer> computer = director.getComputer();

    // 展示产品详情  
    computer->showDetails();

    return 0;
}

Processor: 3500 MHz, 6 cores
Memory: 16 GB, DDR4 RAM


3.2 创建流程固定的场景下使用建造者模式

在创建流程固定的场景下,可以使用一个简单的 Builder 类来封装一个固定流程的构建过程。这种场景下,Builder 类会提供一系列的方法来逐步构建对象,并最终提供一个方法来获取构建好的对象。客户端代码则直接调用 Builder 的方法来构建对象。
如下为样例代码:

#include <iostream>  
#include <memory>  
#include <string>  

// 产品类  
class Product 
{
public:
    void show() const {
        std::cout << "Product built with parts: " << partA << ", " << partB << ", " << partC << std::endl;
    }

public:
    std::string partA;
    std::string partB;
    std::string partC;
};

// 建造者类  
class Builder 
{
public:
    Builder() { m_product = std::make_shared<Product>(); }
    // 初始化产品  
    void setPartA(const std::string& partA) { m_product->partA = partA; }
    void setPartB(const std::string& partB) { m_product->partB = partB; }
    void setPartC(const std::string& partC) { m_product->partC = partC; }

    // 构建并返回产品  
    std::shared_ptr<Product> build() {
        // 在这里可以添加一些额外的构建逻辑
        return m_product;
    }

private:
    std::shared_ptr<Product> m_product;
};
 
int main() 
{
    // 创建建造者对象  
    Builder builder;

    // 通过建造者设置产品的各个部分  
    builder.setPartA("Part A content");
    builder.setPartB("Part B content");
    builder.setPartC("Part C content");

    // 构建并获取产品  
    auto product = builder.build();

    // 展示产品  
    product->show();

    return 0;
}

上面代码的输出为:

Product built with parts: Part A content, Part B content, Part C content

在上面代码中,Product 类是一个简单的产品类,包含三个私有成员变量。Builder 类封装了 Product 对象的构建过程,它提供了三个方法来设置产品的各个部分,以及一个 Build 方法来构建并返回产品对象。

在 main 函数中,客户端代码创建了 Builder 对象,并通过调用 setPartA、setPartB 和 setPartC 方法来设置产品的各个部分。然后,调用 Build 方法来构建产品对象,并存储在 std::shared_ptr 中。最后,调用Show方法来展示构建好的产品。

上面代码展示了如何在创建流程固定的情况下使用建造者模式。Builder 类确保了产品总是按照相同的步骤和顺序被构建,而客户端代码则不需要了解具体的构建细节。这有助于保持代码的清晰和易于维护。

4、建造者模式与工厂模式的比较

建造者模式和工厂模式都是面向对象设计模式中常用的创建型模式,它们的主要区别在于关注点、对象创建过程以及复杂度。

关注点: 工厂模式主要关注对象的创建,而建造者模式不仅关注对象的创建,还关注对象的组成部分以及这些部分的构建顺序。
对象创建过程: 工厂模式通常提供一个统一的接口来创建对象,而不需要知道具体创建对象的类。而建造者模式则更加关注对象的构建过程,它允许用户逐步添加对象的各个部分,并控制这些部分的构建顺序。
复杂度: 工厂模式通常用于创建简单对象,而建造者模式更适合用于创建复杂对象。建造者模式允许用户将复杂对象的构建过程分解为多个步骤,每个步骤只关注对象的一个或几个部分,从而降低了构建过程的复杂度。

总的来说,工厂模式和建造者模式都是用于创建对象的模式,但它们在关注点、对象创建过程以及复杂度上有所不同。选择哪种模式取决于具体的应用场景和需求。

                        
原文链接:https://blog.csdn.net/h8062651/article/details/136311165

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值