工厂模式是一种创建型设计模式,它提供了一种封装对象创建过程的方式。在工厂模式中,我们将对象的实例化过程移到一个独立的工厂类中,客户端通过调用工厂类的方法来创建对象,而不是直接使用 new 关键字实例化对象。
工厂模式有多种变体,其中最常见的是简单工厂模式、工厂方法模式和抽象工厂模式。
假设我们有一个图形类 Shape
,它有两个派生类 Circle
和 Rectangle
。我们使用工厂模式来创建这些图形对象。首先,我们定义一个抽象的基类 Shape
,它声明了一个纯虚函数 draw()
:
class Shape {
public:
virtual void draw() = 0;
};
然后,我们创建两个派生类 Circle
和 Rectangle
,它们实现了 draw()
函数:
class Circle : public Shape {
public:
void draw() {
cout << "Drawing a circle." << endl;
}
};
class Rectangle : public Shape {
public:
void draw() {
cout << "Drawing a rectangle." << endl;
}
};
接下来,我们定义一个工厂类 ShapeFactory
,它根据客户端传入的参数创建相应的图形对象:
class ShapeFactory {
public:
Shape* createShape(string type) {
if (type == "circle") {
return new Circle();
} else if (type == "rectangle") {
return new Rectangle();
} else {
return nullptr;
}
}
};
最后,我们可以在客户端代码中使用工厂类来创建图形对象:
int main() {
ShapeFactory factory;
Shape* shape1 = factory.createShape("circle");
shape1->draw(); // 输出:Drawing a circle.
Shape* shape2 = factory.createShape("rectangle");
shape2->draw(); // 输出:Drawing a rectangle.
delete shape1;
delete shape2;
return 0;
}
在上面的示例中,客户端通过调用 ShapeFactory
的 createShape()
方法来创建图形对象,而不需要直接使用 new
关键字。这样,客户端与具体的图形类解耦,可以通过工厂类来创建不同的图形对象,而无需关心对象创建的具体细节。
工厂模式的优点在于它可以提供一种灵活的对象创建方式,可以根据需求动态地创建不同类型的对象。此外,工厂模式也符合单一职责原则,将对象创建的逻辑封装在工厂类中,使得代码更加可维护和可扩展。
工厂模式的引入主要是为了解决以下设计问题:
-
对象的创建和使用耦合度高:在传统的对象创建方式中,客户端代码通常需要直接使用具体类的构造函数来创建对象。这导致客户端与具体类之间存在紧耦合关系,一旦需要更换具体类或者添加新的类,就需要修改客户端代码。工厂模式通过引入工厂类,将对象的创建过程封装起来,降低了客户端与具体类之间的耦合度。
-
代码复杂度高:当对象的创建过程比较复杂,涉及到多个步骤或者依赖其他对象时,直接在客户端代码中进行对象的创建会导致代码复杂度增加。工厂模式将对象的创建过程集中在工厂类中,可以隐藏对象创建的复杂性,使得客户端代码更加简洁。
-
需要隐藏具体类的实现细节:有时候,我们希望将具体类的实现细节隐藏起来,只向客户端暴露抽象的接口。工厂模式可以通过工厂类来创建具体类的对象,并将对象返回给客户端,客户端只需要通过抽象接口来使用对象,无需知道具体类的实现细节。
-
实现对象创建的灵活性:工厂模式可以根据需求动态地创建不同类型的对象,而无需修改客户端代码。当需要添加新的具体类时,只需要修改工厂类的代码,而不需要修改客户端代码。这提供了一种灵活的对象创建方式,使得系统能够更好地应对变化和扩展。
同样也带来了一些弊端:
-
违反开放封闭原则:当需要添加新的具体类时,必须修改工厂类的代码以支持新类的创建,那么工厂类永远不可能封闭。这违反了开放封闭原则,即对修改关闭,对扩展开放。每次添加新的类都需要修改工厂类,可能导致工厂类变得庞大而复杂。虽然可以通过创建一个工厂类的子类来通过多态实现这一点,但是这也是以新建一个类作为代价的。
-
开放封闭原则?
-