构建器模式有助于将复杂对象的构造与其表示形式分开,以便相同的施工过程可以产生不同的表示(输出)。
让我们看看它可以解决什么样的问题。
构建器模式解决了一个非常具体的问题:望远镜构造函数。要理解它,让我们假设我们有以下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);
简而言之,建筑商设计模式:
-
允许使用相同的施工过程创建对象的不同表示。
-
简化了复杂对象的创建
鉴于构建器模式设置了一种构造新对象的方法,因此可以理解地将其归类为创建设计模式。
建筑商设计模式参与者
构建器设计模式具有四个主要参与者:
-
导演:导演是使用构建器的界面来构建复杂对象的导演。
-
建筑商:提供一个界面来创建复杂对象/产品的组件。
-
具体建筑商:此演员创建了复杂对象所需的所有部分。它包含对最终产品/输出的引用。因此,一旦对象构建完成,客户就从该演员那里获取最终产品。
-
产品:这是要构建的最终对象。它提供了构建最终对象的所有部分并组装它们的接口。
导演执行构建器模式的决定性过程,分离 生产的 从客户。
客户端:
-
创建混凝土构建器为所需产品的类对象。
-
创建导演对象。
-
注入混凝土构建器类对象,在第一步中创建的导演。。
-
向 构造对象。
-
从混凝土构建器类对象中获取最终产品。
建筑商的设计模式现实生活
要解释建筑商的设计模式,让我们以汉堡餐厅的现实生活例子,在那里订购一顿饭。这顿饭可以由主要物品(芝士汉堡,鸡肉汉堡等),侧面物品(炸薯条等)和饮料(可乐,咖啡)组成。
在这种情况下,该命令将传递给前台主管,后者担任董事。他将把命令传递给主要厨师,主厨又要求各自的厨师(混凝土建筑商)准备询问的饭菜。整个过程发生在幕后。客户不知道厨房正在发生什么以执行他的订单。但是,他在桌子上得到了订单。
构建器设计模式UML图
让我们以车辆的构建示例,其中制造了不同类型的车辆,例如汽车,自行车等。这是最终产品。
IVehicleBuilder
是用于创建最终产品/对象的一部分的接口。最终组装过程在 product 中描述。
CarBuilder
和BikeBuilder
是
的具体实现
IVehicleBuilder
。前三种方法适合发动机,轮胎和车前大灯。 GetVehicle()
将返回最终产品。
最后,VehiclePlant
将担任董事。它最终负责构造车辆,并使用IVehicleBuilder
接口构建产品。 它使用相同的构造方法来创建不同类型的车辆。
班级图
以下图形显示了构建器模式的UML类图由几个实体组成彼此相互作用。
序列图
执行
在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()
优势与缺点
好处
由于施工过程与最终对象/产品完全隔离,因此您可以轻松更改构建产品所需的步骤。
由于导演不了解建筑商流程,并且构建过程不必更改,因此您可以轻松地插入新混凝土构建器类来构建新产品。
缺点
产品,混凝土构建器和构建器界面之间存在紧密的耦合。因此,任何类别的变化都需要所有其他类别的更改。这使得任何更改 模式有点困难。
另外,如果我们想要一个可变的对象(创建过程结束后可以修改的对象),我们不应使用此模式。
最后一句话
构建器模式确实是解决复杂对象创建问题的强大模式。
但是,许多程序员可以试图使用构建器设计模式,并忽略更简单,更优雅的解决方案。因此,作为拇指规则,如果可以轻松构造对象并且具有有限数量的构造函数参数,则无需使用构建器模式。
如果:
-
当我们要创建一个复杂的对象时,该对象由多个部分和创建步骤组成。这些步骤中的每一个都可能需要遵循特定的顺序。
-
我们想将施工过程与其表示形式或输出相结合。最终,这将帮助我们在需要时插入更多混凝土构建器。