2.工厂相关(简单工程、工厂方法、抽象工厂)——设计模式入门系列

工厂模式是一种创建型设计模式,目的是将对象的创建过程与其使用过程分离,从而提高代码的可维护性、扩展性和灵活性。工厂模式主要包括三种常见的形式:简单工厂模式工厂方法模式、和抽象工厂模式。每种模式都有各自的特点、应用场景及优缺点。

1. 简单工厂模式(Simple Factory Pattern)

概述

简单工厂模式又称为静态工厂方法模式,是由一个工厂类决定创建哪一种产品类的实例。客户端通过工厂类的静态方法创建产品,而不需要直接使用new关键字。

优点

  • 简化对象创建:客户端无需关注对象的创建细节,直接通过工厂类获取产品实例。
  • 集中管理对象创建:通过一个工厂类来管理对象的创建逻辑,便于修改和维护。

缺点

  • 不符合开闭原则:每新增一个产品类型,都需要修改工厂类的代码。
  • 扩展性差:当产品种类较多时,工厂类可能会变得臃肿。

适用场景

  • 创建对象较少:产品种类不多的情况下使用简单工厂模式能够有效管理对象创建。
  • 客户端不关心产品的具体类型:客户端只需要得到产品实例,而不需要知道产品的具体实现。

类图

+------------------+
|    Product       |  (抽象产品类)
+------------------+
        ^
        |
+------------------+                 +------------------+
| ConcreteProductA |                 | ConcreteProductB |  (具体产品类)
+------------------+                 +------------------+
        ^
        |
+------------------+
| SimpleFactory    |  (工厂类)
+------------------+
| + createProduct(type): Product     |
+------------------------------------+
        |
+------------------+
|    Client        |  (客户端)
+------------------+
| + useProduct()   |
+------------------+
        |
        v
+------------------+
|   Product        |
+------------------+

2. 工厂方法模式(Factory Method Pattern)

概述

工厂方法模式通过定义一个创建对象的接口,让子类决定实例化哪个类。工厂方法将对象的实例化推迟到子类中实现。

优点

  • 符合开闭原则:可以通过新增具体工厂来扩展系统,而无需修改现有的代码。
  • 更高的灵活性:客户端可以选择不同的工厂来创建不同的产品。
  • 更符合面向对象设计:将对象创建的责任转移给具体的工厂子类,使得系统更具可扩展性。

缺点

  • 增加代码复杂度:每增加一种产品类型,就需要增加一个新的具体工厂类。
  • 类数量增加:随着产品种类的增加,系统中会有较多的具体工厂类,可能导致代码量增多。

适用场景

  • 系统结构稳定,新增产品类较多:需要经常添加新产品类的情况下适合使用工厂方法模式。
  • 需要不同的产品创建逻辑:当不同产品的创建过程有显著差异时,可以采用工厂方法模式。

类图

+------------------+
|    Product       |  (抽象产品类)
+------------------+
        ^
        |
+------------------+                 +------------------+
| ConcreteProductA |                 | ConcreteProductB |  (具体产品类)
+------------------+                 +------------------+
        ^                                    ^
        |                                    |
+------------------+                 +------------------+ 
|   Factory        |                 |  Factory         |  (抽象工厂)
| MethodA          |                 | MethodB          |
+------------------+                 +------------------+
| + createProduct(): Product         | + createProduct(): Product
+------------------+                 +------------------+
        ^                                    ^
        |                                    |
+------------------+                 +------------------+ 
| ConcreteFactoryA |                 | ConcreteFactoryB |  (具体工厂)
+------------------+                 +------------------+
| + createProduct(): Product         | + createProduct(): Product
+------------------+                 +------------------+
        |                                    |
+------------------+                 +------------------+ 
|    Client        |  (客户端)       |    Client        |
+------------------+                 +------------------+
| + useProduct()   |                 | + useProduct()   |
+------------------+                 +------------------+
        |                                    |
        v                                    v
+------------------+                 +------------------+ 
|   Product        |                 |   Product        |
+------------------+                 +------------------+

3. 抽象工厂模式(Abstract Factory Pattern)

概述

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。它通常用于创建一族产品,而不是一个具体的产品。

优点

  • 产品族创建一致性:确保一系列相关的产品能够被一致地创建。
  • 符合开闭原则:新增产品族时,只需扩展一个新的具体工厂,无需修改现有系统。
  • 更高的抽象层次:将“工厂”抽象成一个更高级别的概念,方便扩展和维护。

缺点

  • 难以支持新产品:新增产品族时,修改的地方较多,扩展难度较大。
  • 复杂度高:比简单工厂和工厂方法模式更加复杂,结构更庞大。

适用场景

  • 系统需要多个产品族:每个产品族中的产品相关或互相依赖。
  • 系统结构稳定:需要保证产品族创建的一致性,且不经常变动。

类图

+------------------------+
|     AbstractProductA    |  (抽象产品类A)
+------------------------+
          ^
          |
+------------------------+
|  ConcreteProductA1      |  (具体产品A1)
+------------------------+
|  ConcreteProductA2      |  (具体产品A2)
+------------------------+

+------------------------+
|     AbstractProductB    |  (抽象产品类B)
+------------------------+
          ^
          |
+------------------------+
|  ConcreteProductB1      |  (具体产品B1)
+------------------------+
|  ConcreteProductB2      |  (具体产品B2)
+------------------------+

+------------------------+
|   AbstractFactory      |  (抽象工厂类)
+------------------------+
| + createProductA(): AbstractProductA  |
| + createProductB(): AbstractProductB  |
+---------------------------------------+
          ^
          |
+------------------------+              +------------------------+
|  ConcreteFactory1      |              |  ConcreteFactory2      |  (具体工厂类)
+------------------------+              +------------------------+
| + createProductA(): ConcreteProductA1 | + createProductA(): ConcreteProductA2 |
| + createProductB(): ConcreteProductB1 | + createProductB(): ConcreteProductB2 |
+---------------------------------------+ +------------------------------------+
          |
+------------------------+
|      Client            |  (客户端)
+------------------------+
| + useProducts()        |
+------------------------+
          |
          v
+------------------------+
|  AbstractProductA,     |  
|  AbstractProductB      | 
+------------------------+

总结与比较

模式 优点 缺点 适用场景
简单工厂模式 1. 简化对象创建
2. 集中管理对象创建
1. 不符合开闭原则
2. 扩展性差
1. 创建对象较少
2. 客户端不关心产品具体类型
工厂方法模式 1. 符合开闭原则
2. 更高的灵活性
3. 更符合面向对象设计
1. 增加代码复杂度
2. 类数量增加
1. 系统结构稳定,新增产品类较多
2. 需要不同的产品创建逻辑
抽象工厂模式 1. 产品族创建一致性
2. 符合开闭原则
3. 更高的抽象层次
1. 难以支持新产品
2. 复杂度高
1. 系统需要多个产品族
2. 系统结构稳定

综合对比

1. 灵活性与扩展性

  • 简单工厂模式虽然实现简单,但其灵活性和扩展性较差,主要体现在工厂类需要频繁修改才能支持新产品。
  • 工厂方法模式通过子类继承和多态机制,增强了系统的灵活性,能够较好地应对新增产品需求,但类的数量会随之增加。
  • 抽象工厂模式在产品族维度上进一步提升了系统的灵活性,能够在不修改已有代码的前提下,轻松添加新的产品族,但却难以支持新增单个产品。

2. 产品创建的一致性

  • 简单工厂模式工厂方法模式更关注单一产品的创建,因此产品创建的一致性较弱。
  • 抽象工厂模式则强调一组相关产品的创建,确保了产品族中的对象具有创建的一致性,非常适合那些要求创建一整套相关或互相依赖对象的场景。

3. 复杂度

  • 简单工厂模式最为简单,容易实现和理解,但不适合复杂产品的创建需求。
  • 工厂方法模式增加了抽象层次,需要更多的类和接口,但其复杂度仍然可控,适合需要频繁扩展的系统。
  • 抽象工厂模式则是三者中最复杂的,虽然提供了更高级别的抽象和更强的产品族一致性,但实现和维护的成本也相应增加。

综合案例

假设我们需要为一个跨平台的应用程序开发一套UI组件库。这个应用程序需要支持Windows、macOS和Linux平台,每个平台的UI组件(如按钮、文本框、菜单等)都具有不同的风格和实现。

使用简单工厂模式

我们可以创建一个简单工厂类,通过传递操作系统类型来返回相应的UI组件实例:

public class SimpleUIFactory {
    public static Button createButton(String osType) {
        switch (osType) {
            case "Windows":
                return new WindowsButton();
            case "macOS":
                return new MacOSButton();
            case "Linux":
                return new LinuxButton();
            default:
                throw new IllegalArgumentException("Unknown OS type");
        }
    }
}

此方法虽然简单,但当需要增加新平台(如Android)时,需要修改工厂类,违反开闭原则。

使用工厂方法模式

为了使系统更灵活,我们可以使用工厂方法模式,为每个平台定义一个工厂接口,并由具体工厂类实现该接口:

public interface UIFactory {
    Button createButton();
}

public class WindowsUIFactory implements UIFactory {
    public Button createButton() {
        return new WindowsButton();
    }
}

public class MacOSUIFactory implements UIFactory {
    public Button createButton() {
        return new MacOSButton();
    }
}

这样,当需要支持新平台时,只需新增一个实现UIFactory接口的工厂类,而无需修改现有代码。

使用抽象工厂模式

如果我们的应用程序需要创建一整套UI组件,而不仅仅是按钮,那么可以采用抽象工厂模式来管理整个产品族:

public interface UIFactory {
    Button createButton();
    TextBox createTextBox();
    Menu createMenu();
}

public class WindowsUIFactory implements UIFactory {
    public Button createButton() {
        return new WindowsButton();
    }

    public TextBox createTextBox() {
        return new WindowsTextBox();
    }

    public Menu createMenu() {
        return new WindowsMenu();
    }
}

public class MacOSUIFactory implements UIFactory {
    public Button createButton() {
        return new MacOSButton();
    }

    public TextBox createTextBox() {
        return new MacOSTextBox();
    }

    public Menu createMenu() {
        return new MacOSMenu();
    }
}

这样,WindowsUIFactoryMacOSUIFactory分别负责创建Windows和macOS平台的整套UI组件,保证了产品族内组件的风格一致性。

开发者补充

在实际项目开发中,选择合适的工厂模式要考虑系统的规模、复杂度以及未来的扩展需求。简单工厂模式适合小型项目或一次性对象创建,而工厂方法模式则适合需要经常扩展的系统。对于需要创建一系列相关对象的大型项目,抽象工厂模式则是最佳选择,但要注意其复杂度。

同时,现代开发中常用的依赖注入框架(如Spring)也可以看作是工厂模式的扩展和演进,进一步提升了代码的解耦和模块化。因此,在使用工厂模式时,结合依赖注入等设计模式,能够让系统设计更加灵活和可扩展。

你可能感兴趣的:(设计模式,设计模式,java,开发语言)