C++ 设计模式之建造者模式
简介
1、建造者模式(Builder)是一种创建型设计模式,主要用于处理在软件构建过程中复杂对象的创建问题。它将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
2、建造者模式 (Builder)应用场景包括但不限于:
2.1、创建复杂对象 :当你想创建一个复杂对象(对象由多个部分构成,且对象的创建需要遵循特定的过程与步骤)时。
2.2、参数多 :当创建一个对象需要许多参数,并且大多数参数都有默认值时,使用建造者比使用重载的构造函数易于阅读和维护。
2.3、构造过程需要独立 :当构造过程必须独立于创建对象的类时,通过使用建造者模式,你可以使客户端不与对象构造的具体实现耦合。
3、建造者模式 (Builder)的构成
3.1、产品(Product):这是最终构建完成的对象,包含一些基本部件和组装方法。
class ProductA
{
public:
std::vector<std::string> parts;
void ListParts();
};
3.2、建造者(Builder):这是一个抽象接口,定义了创建产品各个部件的抽象方法。
class Builder
{
public:
virtual ~Builder() {};
virtual void ProducePartA() = 0;
};
3.3、具体建造者(ConcreteBuilder):实现了Builder接口,完成具体产品的构建。
class ConcreteBuilder : public Builder
{
private:
ProductA* product;
public:
ConcreteBuilder();
~ConcreteBuilder();
void Reset();
void ProducePartA();
ProductA* GetProduct();
};
3.4、指挥者(Director):负责安排已有模块的顺序,然后指导它们完成一个复杂对象(即产品)的构建工作。
class Director
{
private:
Builder* builder;
public:
void SetBuilder(Builder* builder);
void BuildMinimalViableProduct();
void BuildFullFeaturedProduct();
};
4、建造者模式 (Builder)的优点:
4.1、封装性 :客户端不需要知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
4.2、建造者独立,容易扩展 :Builder独立于其他组件,方便扩展。
4.3、便于控制细节风险 :因为具体的建造者是独立的,所以可以对建造过程逐步细化,而不对其他模块产生任何影响。
5、建造者模式 (Builder)的缺点:
5.1、产品的组成部分必须相同 :建造者模式所创建的产品通常具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式。
5.2、增加系统的复杂度 :增加了多个新类,会增加系统的理解和实现难度。
简单示例
1、定义
// 产品
class ProductA
{
public:
std::vector<std::string> parts;
void ListParts();
};
// 建造者
class Builder
{
public:
virtual ~Builder() {};
virtual void ProducePartA() = 0;
virtual void ProducePartB() = 0;
virtual void ProducePartC() = 0;
};
// 具体建造者
class ConcreteBuilder : public Builder
{
private:
ProductA* product;
public:
ConcreteBuilder();
~ConcreteBuilder();
void Reset();
void ProducePartA();
void ProducePartB();
void ProducePartC();
void ProducePartD();
ProductA* GetProduct();
};
// 指挥者
class Director
{
private:
Builder* builder;
public:
void SetBuilder(Builder* builder);
void BuildMinimalViableProduct();
void BuildFullFeaturedProduct();
};
// 客户端调用
class ClientCode
{
public:
void Run(Director& director);
};
2、实现
void ProductA::ListParts()
{
std::cout << "Product parts:";
for (auto part : parts)
{
if (part == parts.back())
{
std::cout << part;
}
else
{
std::cout << part << ", ";
}
}
std::cout << std::endl << std::endl;
}
ConcreteBuilder::ConcreteBuilder()
{
Reset();
}
ConcreteBuilder::~ConcreteBuilder()
{
if (product)
{
delete product;
}
}
void ConcreteBuilder::Reset()
{
product = new ProductA();
}
void ConcreteBuilder::ProducePartA()
{
product->parts.push_back("ProducePartA");
}
void ConcreteBuilder::ProducePartB()
{
product->parts.push_back("ProducePartB");
}
void ConcreteBuilder::ProducePartC()
{
product->parts.push_back("ProducePartC");
}
void ConcreteBuilder::ProducePartD()
{
product->parts.push_back("ProducePartD");
}
ProductA* ConcreteBuilder::GetProduct()
{
ProductA* tmp = product;
Reset();
return tmp;
}
void Director::SetBuilder(Builder* builder)
{
this->builder = builder;
}
void Director::BuildMinimalViableProduct()
{
builder->ProducePartA();
}
void Director::BuildFullFeaturedProduct()
{
builder->ProducePartA();
builder->ProducePartB();
builder->ProducePartC();
}
void ClientCode::Run(Director& director)
{
ConcreteBuilder* build = new ConcreteBuilder();
director.SetBuilder(build);
std::cout << "方式一:" << std::endl;
director.BuildMinimalViableProduct();
auto pro = build->GetProduct();
pro->ListParts();
delete pro;
std::cout << "方式二:" << std::endl;
director.BuildFullFeaturedProduct();
pro = build->GetProduct();
pro->ListParts();
delete pro;
std::cout << "方式三(自定义):" << std::endl;
build->ProducePartA();
build->ProducePartC();
build->ProducePartD();
build->GetProduct()->ListParts();
delete build;
}
3、调用
ClientCode cli;
Director dir;
cli.Run(dir);