介绍:
不指定具体类的情况下创建对象的方法。核心思想是将对象的创建过程封装在一个工厂类中,通过工厂类的方法来创建对象。(通俗来说:一个工厂,它负责生产各种类型的产品(对象)。当你需要一个新的产品时,只需告诉工厂你需要什么类型的产品,工厂就会生产出相应的产品。你不需要知道具体的生产过程,也不需要关心产品的创建细节。)
简单案例:
// 基类
class Shape {
public:
virtual void draw() = 0;
};
// 派生类
class Circle : public Shape {
public:
void draw() override {
std::cout << "Drawing a circle"<< std::endl;
}
};
class Rectangle : public Shape {
public:
void draw() override {
std::cout << "Drawing a rectangle"<< std::endl;
}
};
// 工厂类
class ShapeFactory {
public:
Shape* createShape(const std::string& shapeType) {
if (shapeType == "circle") {
return new Circle();
} else if (shapeType == "rectangle") {
return new Rectangle();
} else {
return nullptr;
}
}
};
int main() {
ShapeFactory factory;
Shape* shape1 = factory.createShape("circle");
Shape* shape2 = factory.createShape("rectangle");
if (shape1) {
shape1->draw();
delete shape1;
}
if (shape2) {
shape2->draw();
delete shape2;
}
return 0;
}
在这个示例中,ShapeFactory
类包含一个createShape
方法,根据传入的字符串参数来创建相应的对象。这个方法将对象的创建过程封装在工厂类中,使得在main
函数中可以直接使用工厂类来创建Circle
和Rectangle
对象,而不需要关心具体的创建过程。
当需要添加新的Shape
类型时,只需要在ShapeFactory
类中添加相应的条件判断,并创建新的对象。这样,就可以在不修改main
函数的情况下创建新的对象。这就是工厂模式的优势,它将对象的创建和使用分离,使得在需要创建新的对象时,只需要修改工厂类,而不需要修改使用该对象的代码。这样可以降低代码之间的耦合度,提高代码的可维护性。
嵌套工厂
在一个工厂类中创建其他工厂类的实例。这种模式通常用于处理具有多个层次的对象创建和管理。在嵌套工厂模式中,一个工厂类负责创建其他工厂类的实例,而这些工厂类又负责创建具体的对象实例。
class Shape {
public:
virtual void draw() const = 0;
};
class Circle : public Shape {
public:
void draw() const override {
std::cout << "Drawing a circle"<< std::endl;
}
};
class Rectangle : public Shape {
public:
void draw() const override {
std::cout << "Drawing a rectangle"<< std::endl;
}
};
class ShapeFactory {
public:
virtual std::unique_ptr<Shape> createShape() const = 0;
};
class CircleFactory : public ShapeFactory {
public:
std::unique_ptr<Shape> createShape() const override {
return std::make_unique<Circle>();
}
};
class RectangleFactory : public ShapeFactory {
public:
std::unique_ptr<Shape> createShape() const override {
return std::make_unique<Rectangle>();
}
};
class NestedFactory {
public:
std::unique_ptr<ShapeFactory> createFactory(const std::string& shapeType) const {
if (shapeType == "circle") {
return std::make_unique<CircleFactory>();
} else if (shapeType == "rectangle") {
return std::make_unique<RectangleFactory>();
} else {
return nullptr;
}
}
};
int main() {
NestedFactory nestedFactory;
std::unique_ptr<ShapeFactory> circleFactory = nestedFactory.createFactory("circle");
std::unique_ptr<Shape> circle = circleFactory->createShape();
circle->draw();
std::unique_ptr<ShapeFactory> rectangleFactory = nestedFactory.createFactory("rectangle");
std::unique_ptr<Shape> rectangle = rectangleFactory->createShape();
rectangle->draw();
return 0;
}
注:
在工厂方法中,可以使用make_shared
来创建共享指针。用 unique_ptr
是因为我们希望返回的对象有唯一的所有者,这样可以避免多个指针共享同一个对象,这可能会导致在不应该删除对象的时候删除它。unique_ptr
和 shared_ptr
都是智能指针,用于自动管理动态分配的内存。unique_ptr
表示唯一所有权,即在任何时刻,只能有一个 unique_ptr
指向给定的对象和管理其生命周期。当 unique_ptr
被销毁时,它所指向的对象也会被删除。另一方面,shared_ptr
允许多个指针共享同一个对象。当最后一个shared_ptr
被销毁时,它所指向的对象才会被删除。
在这个例子中,我们希望工厂方法创建一个新的形状对象,并将其所有权移交给调用者。因此,使用 unique_ptr
是最合适的。如果我们使用shared_ptr
,那么工厂方法将保留对新对象的引用,这可能不是我们想要的行为。
抽象工厂
提供了一种创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。抽象工厂模式的主要目的是将对象创建过程与客户端代码分离,以便在不修改客户端代码的情况下更改对象创建过程。
说人话举个例子:
假设你是一个汽车制造商,你想要生产两种类型的汽车:轿车和卡车。每辆汽车都需要一个发动机、一个底盘和其他一些零件。为了简化生产过程,你决定将这些零件的生产外包给其他公司。
现在,你有两种选择:
1.针对每种汽车类型,分别找到一家供应商,让他们为你生产所需的零件。这种方法的问题是,如果你将来想要增加第三种汽车类型,你需要再次寻找新的供应商,这会增加管理和协调的难度。
2.找到一家能够生产所有汽车所需零件的供应商。这家供应商可以为你提供一系列相关的零件,而你只需要告诉他们你需要哪种类型的零件。这就是抽象工厂模式的原理。
抽象工厂模式中,有以下几个角色
1.抽象工厂(Abstract Factory):它是一个接口,定义了一组用于创建相关产品的操作。在这个例子中,抽象工厂可以是一个接口,定义了创建发动机、底盘等零件的方法。
2.具体工厂(Concrete Factory):它是抽象工厂的实现,负责创建具体的产品。在这个例子中,具体工厂可以是与供应商A、B等合作的类,它们实现了抽象工厂接口,并提供了创建具体零件的方法。
3.抽象产品(Abstract Product):它是一个接口,描述了相关产品的共同特征。在这个例子中,抽象产品可以是发动机、底盘等零件的接口。
4.具体产品(Concrete Product):它是抽象产品的实现,代表了具体的零件。在这个例子中,具体产品可以是供应商A生产的发动机、底盘等零件的具体实现。
通过使用抽象工厂模式,你可以轻松地切换供应商,而不需要修改客户端代码。例如,如果你想更换供应商,只需创建一个新的具体工厂,实现抽象工厂接口,并让客户端代码使用新的具体工厂即可。
//首先,定义一个抽象工厂接口
class AbstractCarPartFactory {
public:
virtual ~AbstractCarPartFactory() {}
virtual unique_ptr<Engine> createEngine() const = 0;
virtual unique_ptr<Chassis> createChassis() const = 0;
};
//然后,创建具体的工厂类,实现抽象工厂接口
class SupplierA_CarPartFactory : public AbstractCarPartFactory
{
public:
unique_ptr<Engine> createEngine() const override {
return make_unique<SupplierA_Engine>();
}
unique_ptr<Chassis> createChassis() const override {
return make_unique<SupplierA_Chassis>();
}
};
class SupplierB_CarPartFactory : public AbstractCarPartFactory {
public:
unique_ptr<Engine> createEngine() const override {
return make_unique<SupplierB_Engine>();
}
unique_ptr<Chassis> createChassis() const override {
return make_unique<SupplierB_Chassis>();
}
};
//定义抽象产品类
class Engine {
public:
virtual ~Engine() {}
virtual void start() const = 0;
};
class Chassis {
public:
virtual ~Chassis() {}
virtual void install() const = 0;
};
//创建具体的产品类,实现抽象产品类
class SupplierA_Engine : public Engine {
public:
void start() const override {
cout << "Starting SupplierA's Engine" << endl;
}
};
class SupplierA_Chassis : public Chassis {
public:
void install() const override {
cout << "Installing SupplierA's Chassis" << endl;
}
};
class SupplierB_Engine : public Engine {
public:
void start() const override {
cout << "Starting SupplierB's Engine" << endl;
}
};
class SupplierB_Chassis : public Chassis {
public:
void install() const override {
cout << "Installing SupplierB's Chassis" << endl;
}
};
int main()
{
unique_ptr<AbstractCarPartFactory> supplierA_factory = make_unique<SupplierA_CarPartFactory>();
unique_ptr<Engine> engineA = supplierA_factory->createEngine();
unique_ptr<Chassis> chassisA = supplierA_factory->createChassis();
engineA->start();
chassisA->install();
unique_ptr<AbstractCarPartFactory> supplierB_factory = make_unique<SupplierB_CarPartFactory>();
unique_ptr<Engine> engineB = supplierB_factory->createEngine();
unique_ptr<Chassis> chassisB = supplierB_factory->createChassis();
engineB->start();
chassisB->install();
}
函数式工厂
函数式工厂使用函数或闭包(如 C++11 中的 lambda 表达式)来创建和返回对象。它通常用于创建具有相同接口但实现不同功能的对象。
class Shape {
public:
virtual ~Shape() {}
virtual void draw() const = 0;
};
class Circle : public Shape {
public:
void draw() const override {
std::cout << "Drawing a Circle"<< std::endl;
}
};
class Square : public Shape {
public:
void draw() const override {
std::cout << "Drawing a Square"<< std::endl;
}
};
std::unique_ptr<Shape> createShape(const std::string& shapeType) {
if (shapeType == "Circle") {
return std::make_unique<Circle>();
} else if (shapeType == "Square") {
return std::make_unique<Square>();
} else {
throw std::runtime_error("Invalid shape type");
}
}
总结
在实际项目中,选择合适的工厂模式需要考虑以下几个因素:
1.系统复杂性:如果系统较简单,只需要创建少量的产品对象,那么可以使用简单的嵌套工厂模式。如果系统较复杂,需要创建多种产品对象,并且这些对象之间存在很强的依赖关系,那么可以考虑使用抽象工厂模式。
2.可扩展性:如果需要在运行时动态地创建产品对象,并且可能会添加新的产品类,那么可以选择抽象工厂模式。抽象工厂模式允许在不修改现有代码的情况下添加新的产品类和工厂类。
3.代码简洁性:如果希望简化代码并减少模板代码,可以考虑使用函数式工厂模式。函数式工厂模式可以避免创建专门的工厂类,使代码更加简洁和易于维护。
4.性能需求:在某些性能敏感的场景下,可能需要避免使用虚函数和多态(虚函数表(VTable)的查找和调用。当调用虚函数时,编译器会生成一个间接调用,通过虚函数表查找并调用相应的函数实现。这个过程涉及到额外的间接调用开销和虚函数表查找开销。),以减少运行时开销。在这种情况下,可以考虑使用嵌套工厂模式或函数式工厂模式,因为它们不依赖于虚函数和多态。