建筑商设计模式很容易解释
#python #java #cpp #designpatterns

构建器模式有助于将复杂对象的构造与其表示形式分开,以便相同的施工过程可以产生不同的表示(输出)。

让我们看看它可以解决什么样的问题。

构建器模式解决了一个非常具体的问题:望远镜构造函数。要理解它,让我们假设我们有以下Vehicle
类的构造函数定义

public Vehicle(int id, String name)
{
    this(id, name, 0, 0);
}

public Vehicle(int id, String name, int number_of_tyres)
{
    this(id, name, number_of_tyres, 0);
}

这可能在较早的阶段看起来不像一个问题,但是如果您有八个可选参数,并且要表示每个有用的组合,则需要256个构造函数。

此外,假设还有另一个构造函数:

public Vehicle(int id, String name, int number_of_headlights)
{
    this(id, name, 0, number_of_headlights);
}

这里的number_of_headlights具有与早期构造函数中提到的number_of_tyres相同的类型。因此,在此处具有不同参数的不同构造函数的多态性概念在这里失败。

望远镜构造函数问题

如果您使用建筑商模式,则可以简单地:

Vehicle vehicle = new VehicleBuilder().SetName("Car").SetTyres(4).SetHeadlights(2);

简而言之,建筑商设计模式:

  1. 允许使用相同的施工过程创建对象的不同表示。

  2. 简化了复杂对象的创建

鉴于构建器模式设置了一种构造新对象的方法,因此可以理解地将其归类为创建设计模式

建筑商设计模式参与者

构建器设计模式具有四个主要参与者:

  • 导演:导演是使用构建器的界面来构建复杂对象的导演。

  • 建筑商:提供一个界面来创建复杂对象/产品的组件。

  • 具体建筑商:此演员创建了复杂对象所需的所有部分。它包含对最终产品/输出的引用。因此,一旦对象构建完成,客户就从该演员那里获取最终产品。

  • 产品:这是要构建的最终对象。它提供了构建最终对象的所有部分并组装它们的接口。

导演执行构建器模式的决定性过程,分离 生产的客户。

客户端:

  1. 创建混凝土构建器为所需产品的类对象。

  2. 创建导演对象。

  3. 注入混凝土构建器类对象,在第一步中创建的导演。。

  4. 构造对象。

  5. 从混凝土构建器类对象中获取最终产品。

建筑商的设计模式现实生活

要解释建筑商的设计模式,让我们以汉堡餐厅的现实生活例子,在那里订购一顿饭。这顿饭可以由主要物品(芝士汉堡,鸡肉汉堡等),侧面物品(炸薯条等)和饮料(可乐,咖啡)组成。

在这种情况下,该命令将传递给前台主管,后者担任董事。他将把命令传递给主要厨师,主厨又要求各自的厨师(混凝土建筑商)准备询问的饭菜。整个过程发生在幕后。客户不知道厨房正在发生什么以执行他的订单。但是,他在桌子上得到了订单。

构建器设计模式UML图

让我们以车辆的构建示例,其中制造了不同类型的车辆,例如汽车,自行车等。这是最终产品

IVehicleBuilder是用于创建最终产品/对象的一部分的接口。最终组装过程在 product 中描述。

CarBuilderBikeBuilder
的具体实现 IVehicleBuilder。前三种方法适合发动机,轮胎和车前大灯。 GetVehicle()将返回最终产品。

最后,VehiclePlant将担任董事。它最终负责构造车辆,并使用IVehicleBuilder接口构建产品。 它使用相同的构造方法来创建不同类型的车辆。

班级图

以下图形显示了构建器模式的UML类图由几个实体组成彼此相互作用。

Builder Pattern Class Diagram

序列图

Builder Pattern Sequence Diagram

执行

在C ++中

ivehiclebuilder类:

class IVehicleBuilder
{
public:
    virtual void FitEngine() = 0;
    virtual void FitTyres() = 0;
    virtual void FitHeadlight() = 0;
    virtual Vehicle GetVehicle() = 0;
};

Carbuilder类:

class CarBuilder : public IVehicleBuilder
{
private:
    Vehicle vehicle;

public:
    void FitEngine() override
    {
        vehicle.AddPart("Engine Added");
    }

    void FitTyres() override
    {
        vehicle.AddPart("Tyres Inserted");
    }

    void FitHeadlight() override
    {
        vehicle.AddPart("Fitted Headlight");
    }

    Vehicle GetVehicle() override
    {
        return vehicle;
    }
};

车辆类:

class Vehicle
{
private:
    vector<string> parts;

public:
    void AddPart(string part)
    {
        parts.emplace_back(part);
    }

    void PrintDetails()
    {
        for (auto &part : parts)
            std::cout << part << "\n";
    }
};

车载类:

class VehiclePlant
{
private:
    IVehicleBuilder& vehicleBuilder;

public:
    VehiclePlant(IVehicleBuilder& vBuilder):
    vehicleBuilder(vBuilder)
    {

    }

    void Construct()
    {
        vehicleBuilder.FitEngine();
        vehicleBuilder.FitTyres();
        vehicleBuilder.FitHeadlight();
    }
};

客户端程序:

int main()
{
    CarBuilder carBuilder;
    VehiclePlant vehiclePlant(carBuilder);

    vehiclePlant.Construct();

    Vehicle vehicle = carBuilder.GetVehicle();

    vehicle.PrintDetails();
}

在Python

from abc import ABC, abstractmethod

class Vehicle:
    def __init__(self):
        self.__parts__ = []

    def AddPart(self, part):
        self.__parts__.append(part)

    def PrintDetails(self):
        for part in self.__parts__:
            print(part)


class IVehicleBuilder(ABC):
    @abstractmethod
    def FitEngine(self):
        pass

    @abstractmethod
    def FitTyres(self):
        pass

    @abstractmethod
    def FitHeadlight(self):
        pass

    @abstractmethod
    def GetVehicle(self):
        pass

class CarBuilder(IVehicleBuilder):
    def __init__(self):
        super().__init__()
        self.__vehicle__ = Vehicle()

    def FitEngine(self):
        self.__vehicle__.AddPart("Engine Added");

    def FitTyres(self):
        self.__vehicle__.AddPart("Tyres Inserted");

    def FitHeadlight(self):
        self.__vehicle__.AddPart("Fitted Headlight");

    def GetVehicle(self):
        return self.__vehicle__;

class VehiclePlant:
    def __init__(self, vBuilder):
        self.__vehicleBuilder__ = vBuilder

    def Construct(self):
        self.__vehicleBuilder__.FitEngine();
        self.__vehicleBuilder__.FitTyres();
        self.__vehicleBuilder__.FitHeadlight();

if __name__ == '__main__':
    carBuilder = CarBuilder()
    vehiclePlant = VehiclePlant (carBuilder);
    vehiclePlant.Construct()
    vehicle = carBuilder.GetVehicle()
    vehicle.PrintDetails()

注意
默认情况下,Python不提供抽象类的支持。但是,Python带有一个模块,该模块为定义 抽象基类(ABC) 提供了基础。 ABC通过将基类的方法作为抽象装饰,然后注册具体类作为抽象基础的实现。用关键字@abstractmethod装饰时,一种方法会变得抽象。
例如(参考从geeksforgeeks.com获取)

from abc import ABC, abstractmethod

class Polygon(ABC):
    @abstractmethod
    def noofsides(self):
        pass


class Triangle(Polygon):
    # overriding abstract method
    def noofsides(self):
        print("I have 3 sides")

# Driver code
R = Triangle()
R.noofsides()

建筑商模式的变化

构建器模式具有稍微修改的版本,其中构建方法 彼此链接。该方法称为流利的构建器

    Vehicle vehicle = carBuilder.FitEngine().FitTyres().FitHeadlight().build();

这是通过从每种构建方法中返回自己来完成的。最终构建方法返回最终对象。此外,请注意,您不需要董事在这里。

在这里,是替代实现:

在C ++中

ivehiclebuilder类

class IVehicleBuilder
{
    using self = IVehicleBuilder;
public:
    virtual self& FitEngine() = 0;
    virtual self& FitTyres() = 0;
    virtual self& FitHeadlight() = 0;
    virtual Vehicle GetVehicle() = 0;
};

Carbuilder类

class CarBuilder: public IVehicleBuilder
{
private:
    using self = CarBuilder;
    Vehicle vehicle;

public:
    self& FitEngine() override
    {
        vehicle.AddPart("Engine Added");
        return *this;
    }

    self& FitTyres() override
    {
        vehicle.AddPart("Tyres Inserted");
        return *this;
    }

    self& FitHeadlight() override
    {
        vehicle.AddPart("Fitted Headlight");
        return *this;
    }

    Vehicle GetVehicle() override
    {
        return vehicle;
    }
};

主要程序

int main()
{
    CarBuilder carBuilder;

    Vehicle vehicle = carBuilder.FitEngine().FitTyres().FitHeadlight().GetVehicle();
    vehicle.PrintDetails();
}

您也可以使用指针代替参考。在这种情况下,定义 fit ...()这样的方法:

self* FitEngine() override
{
    vehicle.AddPart("Engine Added");
    return this;
}

用 - >运算符替换您的链电话:

Vehicle vehicle = carBuilder->FitEngine()->FitTyres()->FitHeadlight()->GetVehicle();

您还可以用功能操作员替换GetVehicle()方法以产生最终产品:

class CarBuilder: public IVehicleBuilder
{
    ...

    Vehicle operator()()
    {
        return vehicle;
    }
};

int main()
{
    CarBuilder carBuilder;
    Vehicle vehicle = carBuilder.FitEngine().FitTyres().FitHeadlight()();
    vehicle.PrintDetails();
}

在Python

class CarBuilder(IVehicleBuilder):
    def __init__(self):
        super().__init__()
        self.__vehicle__ = Vehicle()

    def FitEngine(self):
        self.__vehicle__.AddPart("Engine Added")
        return self

    def FitTyres(self):
        self.__vehicle__.AddPart("Tyres Inserted");
        return self

    def FitHeadlight(self):
        self.__vehicle__.AddPart("Fitted Headlight");
        return self

    def GetVehicle(self):
        return self.__vehicle__;

if __name__ == '__main__':
    vehicle = CarBuilder().FitEngine().FitTyres().FitHeadlight().GetVehicle()
    vehicle.PrintDetails()

优势与缺点

好处

由于施工过程与最终对象/产品完全隔离,因此您可以轻松更改构建产品所需的步骤。

由于导演不了解建筑商流程,并且构建过程不必更改,因此您可以轻松地插入新混凝土构建器类来构建新产品。

缺点

产品,混凝土构建器和构建器界面之间存在紧密的耦合。因此,任何类别的变化都需要所有其他类别的更改。这使得任何更改 模式有点困难。

另外,如果我们想要一个可变的对象(创建过程结束后可以修改的对象),我们不应使用此模式。

最后一句话

构建器模式确实是解决复杂对象创建问题的强大模式。

但是,许多程序员可以试图使用构建器设计模式,并忽略更简单,更优雅的解决方案。因此,作为拇指规则,如果可以轻松构造对象并且具有有限数量的构造函数参数,则无需使用构建器模式。

如果:

  • 当我们要创建一个复杂的对象时,该对象由多个部分和创建步骤组成。这些步骤中的每一个都可能需要遵循特定的顺序。

  • 我们想将施工过程与其表示形式或输出相结合。最终,这将帮助我们在需要时插入更多混凝土构建器