定义与概念
工厂模式是一种创建型设计模式。它的主要目的是将对象的创建和使用分离。在软件系统中,当创建对象的过程比较复杂或者需要根据不同的条件创建不同类型的对象时,工厂模式就可以发挥作用。
例如,在一个图形绘制程序中,根据用户的选择来创建不同的图形(圆形、矩形等),如果没有工厂模式,在代码的各个地方都可能会有创建图形对象的代码,这样会使代码变得混乱且难以维护。而使用工厂模式,就可以将图形对象的创建集中在一个工厂类中进行。
模式结构
- 工厂类(Factory Class):
这是工厂模式的核心。它负责创建产品对象。工厂类通常包含一个或多个创建方法,这些方法根据传入的参数或者内部的逻辑来决定创建哪种具体的产品对象。例如,有一个图形工厂类(ShapeFactory),它可以有一个createShape方法,根据传入的图形类型参数(如 “circle” 或 “rectangle”)来创建相应的图形对象。 - 产品抽象类(Product Abstract Class):
定义了产品对象的接口,它规定了产品对象应该具有的方法和属性。所有具体的产品对象都需要实现这个抽象类。以图形为例,有一个抽象图形类(Shape),它可能定义了draw方法,用于绘制图形。 - 具体产品类(Concrete Product Class):
实现了产品抽象类的接口。在图形的例子中,具体产品类可以是Circle(圆形)类和Rectangle(矩形)类。Circle类会实现draw方法来绘制圆形,Rectangle类会实现draw方法来绘制矩形。
代码示例
- 首先是产品抽象类:
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();
}
return nullptr;
}
};
- 使用示例:
int main() {
ShapeFactory factory;
Shape* circle = factory.createShape("circle");
circle->draw();
Shape* rectangle = factory.createShape("rectangle");
rectangle->draw();
delete circle;
delete rectangle;
return 0;
}
这段代码输出了绘制圆形和绘制矩形的信息。通过工厂类,根据传入的参数来创建不同的图形对象,并调用它们的draw方法进行绘制。
优点
- 解耦对象的创建和使用:
使得代码的依赖关系更加清晰。在使用产品对象的代码中,不需要关心对象是如何创建的,只需要从工厂类获取即可。例如,在一个大型的游戏开发中,游戏场景中的各种道具对象可以通过道具工厂来创建,游戏场景的逻辑代码只需要使用这些道具对象,而不用管它们是怎么制作出来的。
提高代码的可维护性和可扩展性:如果要添加新的产品类型,只需要在工厂类中添加相应的创建方法和新的具体产品类。例如,在图形绘制程序中,如果要添加三角形这种新的图形,只需要创建Triangle类并在工厂类中添加创建三角形的逻辑。 - 便于代码的复用:
工厂类可以在多个地方被复用。例如,不同的模块都需要创建图形对象,那么这个图形工厂类就可以被这些模块共享使用。
缺点
- 工厂类可能会变得复杂:
当需要创建的产品类型较多时,工厂类中的创建方法会变得很长,逻辑也会变得复杂。例如,在一个工厂类要创建几十种不同类型的产品时,create方法中的判断条件会很多。
不适合简单的对象创建场景:如果对象的创建过程非常简单,使用工厂模式可能会增加不必要的代码复杂度。例如,只是简单地创建一个整数对象,就没有必要使用工厂模式。
适用场景 - 对象创建过程复杂:
当对象的创建需要经过多个步骤,或者需要配置很多参数时,使用工厂模式可以将这些复杂的创建过程封装在工厂类中。例如,在创建数据库连接对象时,需要配置数据库的类型、地址、用户名和密码等参数,通过工厂模式可以将这些配置过程封装在工厂类中。 - 根据不同条件创建不同对象:
在需要根据用户输入、配置文件或者运行时的其他条件来创建不同类型的对象时,工厂模式很适用。比如,在一个图形编辑软件中,根据用户选择的工具(如画圆工具、画矩形工具)来创建不同的图形对象。