GoF 23种经典的设计模式——工厂模式

2024-01-13 09:52:46 浏览数 (1)

工厂模式是一种创建型设计模式,它提供了一种封装对象创建过程的方式。在工厂模式中,我们将对象的实例化过程移到一个独立的工厂类中,客户端通过调用工厂类的方法来创建对象,而不是直接使用 new 关键字实例化对象。

工厂模式有多种变体,其中最常见的是简单工厂模式、工厂方法模式和抽象工厂模式。

假设我们有一个图形类 Shape,它有两个派生类 CircleRectangle。我们使用工厂模式来创建这些图形对象。首先,我们定义一个抽象的基类 Shape,它声明了一个纯虚函数 draw()

代码语言:javascript复制
class Shape {
 public:
     virtual void draw() = 0;
 };

然后,我们创建两个派生类 CircleRectangle,它们实现了 draw() 函数:

代码语言:javascript复制
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,它根据客户端传入的参数创建相应的图形对象:

代码语言:javascript复制
class ShapeFactory {
 public:
     Shape* createShape(string type) {
         if (type == "circle") {
             return new Circle();
        } else if (type == "rectangle") {
             return new Rectangle();
        } else {
             return nullptr;
        }
    }
 };

最后,我们可以在客户端代码中使用工厂类来创建图形对象:

代码语言:javascript复制
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;
 }

在上面的示例中,客户端通过调用 ShapeFactorycreateShape() 方法来创建图形对象,而不需要直接使用 new 关键字。这样,客户端与具体的图形类解耦,可以通过工厂类来创建不同的图形对象,而无需关心对象创建的具体细节。

工厂模式的优点在于它可以提供一种灵活的对象创建方式,可以根据需求动态地创建不同类型的对象。此外,工厂模式也符合单一职责原则,将对象创建的逻辑封装在工厂类中,使得代码更加可维护和可扩展。

工厂模式的引入主要是为了解决以下设计问题:

  1. 对象的创建和使用耦合度高:在传统的对象创建方式中,客户端代码通常需要直接使用具体类的构造函数来创建对象。这导致客户端与具体类之间存在紧耦合关系,一旦需要更换具体类或者添加新的类,就需要修改客户端代码。工厂模式通过引入工厂类,将对象的创建过程封装起来,降低了客户端与具体类之间的耦合度。
  2. 代码复杂度高:当对象的创建过程比较复杂,涉及到多个步骤或者依赖其他对象时,直接在客户端代码中进行对象的创建会导致代码复杂度增加。工厂模式将对象的创建过程集中在工厂类中,可以隐藏对象创建的复杂性,使得客户端代码更加简洁。
  3. 需要隐藏具体类的实现细节:有时候,我们希望将具体类的实现细节隐藏起来,只向客户端暴露抽象的接口。工厂模式可以通过工厂类来创建具体类的对象,并将对象返回给客户端,客户端只需要通过抽象接口来使用对象,无需知道具体类的实现细节。
  4. 实现对象创建的灵活性:工厂模式可以根据需求动态地创建不同类型的对象,而无需修改客户端代码。当需要添加新的具体类时,只需要修改工厂类的代码,而不需要修改客户端代码。这提供了一种灵活的对象创建方式,使得系统能够更好地应对变化和扩展。

同样也带来了一些弊端:

  • 违反开放封闭原则:当需要添加新的具体类时,必须修改工厂类的代码以支持新类的创建,那么工厂类永远不可能封闭。这违反了开放封闭原则,即对修改关闭,对扩展开放。每次添加新的类都需要修改工厂类,可能导致工厂类变得庞大而复杂。虽然可以通过创建一个工厂类的子类来通过多态实现这一点,但是这也是以新建一个类作为代价的。
  • 开放封闭原则?
    • 软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。简而言之,开放封闭原则要求我们设计的软件实体应该能够在不修改其源代码的情况下进行扩展,而只通过添加新的代码来实现新的功能或行为。这样做的好处是,我们可以在不破坏现有代码的情况下对系统进行扩展,降低了系统的维护成本,并提高了代码的可复用性和可扩展性。

------本页内容已结束,喜欢请分享------


0 人点赞