目录

  1. 创建型设计模式简介

  2. 单例模式(Singleton Pattern)

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

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

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

  6. 建造者模式(Builder Pattern)

  7. 原型模式(Prototype Pattern)

  8. 创建型模式的对比与总结

  9. 选择合适的创建型模式

  10. 总结


1. 创建型设计模式简介

创建型设计模式旨在简化对象的创建过程,隐藏创建逻辑,提升系统的灵活性和可扩展性。这类模式通过封装对象的创建方式,使得系统不依赖于具体的类,实现对象创建的抽象化和多样化。常见的创建型模式包括:

  • 单例模式(Singleton Pattern)

  • 简单工厂模式(Simple Factory Pattern)

  • 工厂方法模式(Factory Method Pattern)

  • 抽象工厂模式(Abstract Factory Pattern)

  • 建造者模式(Builder Pattern)

  • 原型模式(Prototype Pattern)


2. 单例模式(Singleton Pattern)

2.1. 定义

单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。它常用于需要全局控制资源的场景,如配置管理、日志记录、数据库连接等。

2.2. 意图

  • 唯一实例:确保系统中某个类只有一个实例存在。

  • 全局访问:提供一个全局访问点,便于在任何地方获取该实例。

2.3. UML 类图

+----------------------------+
|      Singleton             |
+----------------------------+
| - instance: Singleton      |
+----------------------------+
| + getInstance(): Singleton |
+----------------------------+

2.4. 适用场景

  • 全局资源控制:如配置管理、日志记录、数据库连接池等。

  • 需要唯一实例:确保系统中只有一个实例存在,避免资源冲突。

2.5. 优缺点

优点:

  1. 控制实例数量:确保系统中只有一个实例,节约资源。

  2. 全局访问点:提供全局访问点,方便在任何地方使用。

缺点:

  1. 难以测试:单例的全局状态可能导致测试变得困难。

  2. 隐藏依赖:通过全局访问点引入依赖,降低代码的透明度。

  3. 并发问题:在多线程环境下,需额外处理同步问题,防止多实例创建。

2.6. 常见误区与解决方案

  • 误区:单例模式等同于全局变量。

    • 解决方案:单例模式不仅提供全局访问,还确保唯一实例,具有更高的控制性和封装性。


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

3.1. 定义

简单工厂模式是一种创建型设计模式,通过一个工厂类根据传入的参数决定创建哪一种具体产品类的实例。它将对象的创建过程集中在一个工厂类中,客户端通过工厂类提供的接口获取所需的对象,无需直接实例化具体类。

3.2. 意图

  • 封装对象创建:将对象的创建过程集中在工厂类中,避免客户端直接依赖具体类。

  • 简化客户端代码:客户端只需调用工厂方法即可获取所需对象,减少了直接实例化的代码量。

  • 集中管理对象创建:所有对象的创建都由工厂类统一管理,便于维护和扩展。

3.3. UML 类图

+----------------------------------------+
|      Factory                           |
+----------------------------------------+
| + createProduct(type: String): Product |
+----------------------------------------+
          |
          |
+-------------------+       +-------------------+
|      Product      |<------| ConcreteProductA  |
+-------------------+       +-------------------+
| + use()           |       | + use()           |
+-------------------+       +-------------------+
                           +-------------------+
                           | ConcreteProductB  |
                           +-------------------+
                           | + use()           |
                           +-------------------+

3.4. 适用场景

  • 对象创建逻辑复杂:如需要进行复杂计算或依赖多个参数。

  • 需要创建多种相似对象:系统中需要创建许多相似但略有不同的对象。

  • 客户端不关心具体类:客户端只需知道所需对象的类型,无需了解具体类的实现细节。

  • 符合开闭原则:需要在不修改客户端代码的情况下,通过扩展工厂类来支持新的产品类型。

3.5. 优缺点

优点:

  1. 封装对象创建:集中管理对象创建过程,客户端无需了解具体类的创建细节。

  2. 简化客户端代码:客户端通过工厂方法获取对象,减少了直接实例化的代码量。

  3. 集中管理对象创建:所有对象的创建由工厂类统一管理,便于维护和扩展。

  4. 符合开闭原则:通过修改工厂类,可以增加新产品的支持,而无需修改客户端代码。

缺点:

  1. 违反单一职责原则:工厂类承担了创建所有产品的职责,可能导致工厂类过于庞大。

  2. 增加系统复杂性:每增加一种产品类型,都需要修改工厂类,增加了工厂类的复杂性。

  3. 不易扩展:对于产品种类频繁变化的系统,简单工厂模式可能不够灵活,难以适应需求变化。

3.6. 常见误区与解决方案

  • 误区1:简单工厂模式等同于工厂方法模式。

    • 事实:简单工厂模式通过一个工厂类创建所有产品,而工厂方法模式通过定义一个抽象工厂接口,让子类决定具体创建哪一种产品。

    • 解决方案:理解两者的区别,简单工厂适用于产品种类不频繁变化的场景,工厂方法适用于产品种类频繁变化或需要扩展的场景。

  • 误区2:简单工厂模式可以代替所有工厂模式。

    • 事实:简单工厂模式虽然简化了对象创建,但在复杂或需要扩展的场景下,工厂方法或抽象工厂模式更为适用。

    • 解决方案:根据系统的复杂性和扩展需求选择合适的工厂模式,不要强行使用简单工厂模式解决所有问题。

  • 误区3:简单工厂模式无需考虑并发问题。

    • 事实:在多线程环境下,工厂类的静态方法可能会导致线程安全问题,特别是在懒加载实例时。

    • 解决方案:确保工厂方法的线程安全,可以通过同步机制或使用线程安全的数据结构来管理。

  • 误区4:简单工厂模式可以解决所有对象创建的问题。

    • 事实:简单工厂模式主要解决对象创建的封装问题,对于对象生命周期管理、复杂依赖注入等问题,可能需要结合其他设计模式。

    • 解决方案:根据具体需求,结合其他设计模式(如依赖注入、单例模式)来完善系统的对象创建和管理。


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

4.1. 定义

工厂方法模式是一种创建型设计模式,通过定义一个创建对象的接口,让子类决定实例化哪一个类。它使得类的实例化延迟到子类。工厂方法模式适用于产品类比较多或复杂,需要通过子类来进行扩展的场景。

4.2. 意图

  • 延迟对象创建:将对象的创建延迟到子类,实现类的实例化延迟化。

  • 符合开闭原则:通过子类扩展,支持更多类型的产品,而无需修改工厂接口或客户端代码。

4.3. UML 类图

+----------------------------+
|       Creator              |
+----------------------------+
| + factoryMethod(): Product |
+----------------------------+
| + someOperation()          |
+----------------------------+
          |
          |
+----------------------------+
|   ConcreteCreatorA         |
+----------------------------+
| + factoryMethod(): Product |
+----------------------------+

+----------------------------+
|   ConcreteCreatorB         |
+----------------------------+
| + factoryMethod(): Product |
+----------------------------+

+----------------------+
|       Product        |
+----------------------+
| + use()              |
+----------------------+
          ^
          |
+----------------------+     +----------------------+
| ConcreteProductA     |     | ConcreteProductB     |
+----------------------+     +----------------------+
| + use()              |     | + use()              |
+----------------------+     +----------------------+

4.4. 适用场景

  • 产品类较多或频繁变化:系统中有大量产品类,且这些产品类经常变化或扩展。

  • 需要通过子类工厂创建不同的产品:不同的工厂子类负责创建不同的产品类,实现职责分离。

  • 需要控制产品类的实例化:工厂方法模式可以控制哪些产品类可以被实例化。

4.5. 优缺点

优点:

  1. 符合开闭原则:通过引入新的具体工厂和产品类,可以扩展系统功能,而无需修改已有代码。

  2. 封装对象创建:将对象的创建过程封装在具体工厂类中,客户端无需了解具体类的创建细节。

  3. 提高代码复用性和可维护性:不同的具体工厂类可以复用相同的创建逻辑,便于维护和管理。

缺点:

  1. 增加类的数量:每种产品类型都需要对应一个具体工厂类,可能导致类的数量增加。

  2. 结构复杂性:相对于简单工厂模式,工厂方法模式的结构更加复杂,需要定义抽象工厂接口和具体工厂类。

  3. 不适用于单一产品的创建:当产品种类较少且不易扩展时,工厂方法模式可能显得过于繁琐。

4.6. 常见误区与解决方案

  • 误区1:认为工厂方法模式比简单工厂模式更好。

    • 事实:工厂方法模式适用于产品类较多或频繁变化的场景,简单工厂模式适用于产品类较少且不易变化的场景。

    • 解决方案:根据系统的需求和产品类的特点选择合适的工厂模式。

  • 误区2:工厂方法模式可以完全取代简单工厂模式。

    • 事实:两者适用的场景不同,工厂方法模式在某些情况下可能过于复杂。

    • 解决方案:根据具体需求评估是否需要使用工厂方法模式,避免过度设计。


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

5.1. 定义

抽象工厂模式是一种创建型设计模式,提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。抽象工厂模式适用于产品族(Family)不变的情况下创建不同系列的产品。

5.2. 意图

  • 创建相关对象:确保创建一系列相关或相互依赖的对象,保证它们能够协同工作。

  • 封装具体类:客户端无需了解具体产品类的实现,减少了系统的耦合度。

5.3. UML 类图

+--------------------------------------+
|     AbstractFactory                  |
+--------------------------------------+
| + createProductA(): AbstractProductA |
| + createProductB(): AbstractProductB |
+--------------------------------------+
          /_\
           |
+--------------------------------------+     +--------------------------------------+
|    ConcreteFactory1                  |     |    ConcreteFactory2                  |
+--------------------------------------+     +--------------------------------------+
| + createProductA(): AbstractProductA |     | + createProductA(): AbstractProductA |
| + createProductB(): AbstractProductB |     | + createProductB(): AbstractProductB |
+--------------------------------------+     +--------------------------------------+

+-------------------------+
|     AbstractProductA    |
+-------------------------+
| + doSomethingA()        |
+-------------------------+
          ^
          |
+-------------------------+
|   ConcreteProductA1     |
+-------------------------+
| + doSomethingA()        |
+-------------------------+
|   ConcreteProductA2     |
+-------------------------+
| + doSomethingA()        |
+-------------------------+

+-------------------------+
|     AbstractProductB    |
+-------------------------+
| + doSomethingB()        |
+-------------------------+
          ^
          |
+-------------------------+
|   ConcreteProductB1     |
+-------------------------+
| + doSomethingB()        |
+-------------------------+
|   ConcreteProductB2     |
+-------------------------+
| + doSomethingB()        |
+-------------------------+

5.4. 适用场景

  • 需要创建一系列相关或相互依赖的对象:如UI组件(按钮、文本框、窗口等)需要在不同平台上保持一致。

  • 系统需要独立于具体产品类的创建:客户端只依赖于抽象工厂和抽象产品接口,减少对具体类的依赖。

  • 需要确保产品族的兼容性:通过同一个具体工厂创建的产品对象能够协同工作,符合设计的一致性。

5.5. 优缺点

优点:

  1. 创建一系列相关对象:通过一个工厂接口,可以创建一系列相关或相互依赖的对象,确保产品族的兼容性。

  2. 符合开闭原则:通过新增具体工厂和产品类,可以扩展系统功能,而无需修改已有代码。

  3. 封装具体类:客户端无需了解具体产品类的实现,降低了系统的耦合度。

  4. 增强系统的灵活性和可扩展性:不同的工厂可以创建不同的产品族,适应多变的需求。

缺点:

  1. 增加类的数量:每增加一个产品族,都需要新增一个具体工厂类和相应的具体产品类,可能导致类的数量迅速增加。

  2. 结构复杂性:结构相对复杂,需要定义抽象工厂接口和多个具体工厂类,增加了系统的复杂性。

  3. 不适用于单一产品的创建:如果系统只需要创建单一类型的产品,抽象工厂模式可能显得过于复杂。

5.6. 常见误区与解决方案

  • 误区1:认为抽象工厂模式可以创建任意数量的产品。

    • 事实:抽象工厂模式通常创建一组相关的产品,而不是任意数量的独立产品。

    • 解决方案:明确产品族的概念,确保工厂模式的一致性和协同作用。

  • 误区2:认为抽象工厂模式可以替代工厂方法模式。

    • 事实:两者适用于不同的场景,抽象工厂模式适用于创建一系列相关对象,工厂方法模式适用于创建单一类型的对象。

    • 解决方案:根据系统需求选择合适的工厂模式,避免混淆两者的使用场景。


6. 建造者模式(Builder Pattern)

6.1. 定义

建造者模式是一种创建型设计模式,提供了一种将一个复杂对象的构建过程与其表示分离的方法,使得同样的构建过程可以创建不同的表示。它允许一步步构建一个复杂对象,并根据需要定制其内部组成部分。

6.2. 意图

  • 分步构建复杂对象:将复杂对象的构建过程分解为多个步骤。

  • 分离构建与表示:使得同样的构建过程可以创建不同的表示。

6.3. UML 类图

+--------------------------------+
|      Director                  |
+--------------------------------+
| - builder: Builder             |
+--------------------------------+
| + setBuilder(builder: Builder) |
| + construct(): Product         |
+--------------------------------+
          |
          |
+------------------------+
|      Builder           |
+------------------------+
| + buildPartA()         |
| + buildPartB()         |
| + getResult(): Product |
+------------------------+
          /_\
           |
+------------------------+      +------------------------+
|   ConcreteBuilder1     |      |   ConcreteBuilder2     |
+------------------------+      +------------------------+
| + buildPartA()         |      | + buildPartA()         |
| + buildPartB()         |      | + buildPartB()         |
| + getResult(): Product |      | + getResult(): Product |
+------------------------+      +------------------------+

+---------------------------+
|        Product            |
+---------------------------+
| - partA: String           |
| - partB: String           |
+---------------------------+
| + setPartA(partA: String) |
| + setPartB(partB: String) |
| + show()                  |
+---------------------------+

6.4. 适用场景

  • 创建复杂对象:对象的创建涉及多个步骤或多个部分,如生成不同类型的文档、构建复杂的用户界面组件。

  • 需要灵活定制对象:允许根据不同的需求定制对象的内部组成部分。

  • 希望通过不同的建造者创建不同的对象表示:如根据不同的配置生成不同的产品版本。

6.5. 优缺点

优点:

  1. 封装复杂的构建过程:将复杂对象的构建过程封装在建造者中,简化客户端代码。

  2. 分离构建与表示:允许同样的构建过程创建不同的表示,增强系统的灵活性。

  3. 符合单一职责原则:建造者专注于产品的构建,不涉及产品的表示或其他业务逻辑。

  4. 易于扩展:通过新增具体建造者,可以轻松扩展系统功能,而无需修改已有代码。

  5. 支持流畅接口:建造者模式可以与流畅接口结合,实现链式调用,提升代码的可读性。

缺点:

  1. 增加类的数量:每个具体建造者需要创建一个新的建造者类,可能导致系统中类的数量增加。

  2. 代码复杂性:对于简单的对象创建,使用建造者模式可能显得过于复杂。

  3. 维护成本:随着产品的复杂性增加,建造者类的实现和维护可能变得更加繁琐。

6.6. 常见误区与解决方案

  • 误区1:认为建造者模式可以替代所有复杂对象的创建。

    • 事实:建造者模式适用于构建过程复杂且需要灵活定制的对象,对于简单对象创建无需使用建造者模式。

    • 解决方案:评估对象创建的复杂性和定制需求,合理选择是否使用建造者模式。

  • 误区2:忽视建造者与指挥者之间的关系。

    • 事实:指挥者在建造者模式中负责管理建造过程,忽视这一角色可能导致构建流程混乱。

    • 解决方案:明确指挥者的职责,确保建造者与指挥者之间的协同作用。


7. 原型模式(Prototype Pattern)

7.1. 定义

原型模式是一种创建型设计模式,提供了一种通过复制现有实例来创建新对象的机制,从而避免了重复的对象创建过程,提高了系统的性能和灵活性。特别适用于对象创建成本较高或复杂的场景。

7.2. 意图

  • 通过复制现有对象创建新对象:避免重复编写创建对象的代码,提高开发效率。

  • 支持动态的对象创建:在运行时根据需要选择合适的原型进行复制,增强系统的灵活性。

  • 减少创建对象的开销:对于创建成本较高或复杂的对象,通过复制可以显著降低系统的资源消耗。

7.3. UML 类图

+------------------------+
|       Prototype        |
+------------------------+
| + clone(): Prototype   |
| + show()               |
+------------------------+
          /_\
           |
+-------------------------+
|   ConcretePrototype     |
+-------------------------+
| - name: String          |
| - age: int              |
+-------------------------+
| + clone(): Prototype    |
| + show()                |
+-------------------------+

7.4. 适用场景

  • 需要频繁复制对象:如游戏中的角色复制、大量相似配置文件的创建。

  • 对象的创建成本较高:如图形编辑器中的复杂图形对象。

  • 希望在运行时动态指定对象类型:通过复制不同的原型对象,可以在运行时灵活决定新对象的类型。

  • 实现对象的多态复制:需要根据上下文复制不同类型的对象,原型模式通过抽象原型接口实现多态复制。

7.5. 优缺点

优点:

  1. 提高性能:通过复制现有对象创建新对象,避免了重复的初始化过程,尤其在对象创建成本较高时显著提升性能。

  2. 动态创建对象:允许在运行时动态地选择和复制不同的原型对象,增强系统的灵活性。

  3. 隐藏复杂创建逻辑:客户端无需了解对象的创建细节,只需复制原型即可获得新对象。

  4. 支持多态复制:通过抽象原型接口,支持不同类型的原型对象被统一复制,促进代码的多态性。

缺点:

  1. 实现复杂性:需要确保所有原型对象都实现了正确的复制方法,特别是在涉及深拷贝和浅拷贝时。

  2. 依赖具体原型:客户端需要了解可用的原型对象,可能导致对具体原型的依赖。

  3. 复制成本:对于某些复杂对象,复制过程本身可能具有一定的开销,尤其是深拷贝操作。

  4. 难以维护:随着系统中原型对象的增多,管理和维护这些原型对象可能变得复杂。

7.6. 常见误区与解决方案

  • 误区1:原型模式适用于所有对象的复制。

    • 事实:原型模式适用于需要频繁复制且复制成本较高的对象,对于简单或轻量级的对象,直接实例化可能更合适。

    • 解决方案:评估对象的复制需求,仅在对象复制确实带来性能提升或简化创建过程时,使用原型模式。

  • 误区2:原型模式无需考虑对象的状态。

    • 事实:在复制对象时,需要确保对象的状态被正确复制,特别是在涉及引用类型或复杂嵌套对象时,需要处理好深拷贝与浅拷贝的问题。

    • 解决方案:正确实现复制方法,确保对象的状态在复制过程中得到准确反映。

  • 误区3:原型模式可以解决所有创建问题。

    • 事实:原型模式主要解决对象复制的问题,对于对象的创建逻辑复杂度或依赖关系,可能需要结合其他设计模式(如工厂模式)一起使用。

    • 解决方案:根据具体需求,结合其他设计模式,完善对象创建和复制的流程。


8. 创建型模式的对比与总结

8.1. 结构对比

下表展示了单例模式简单工厂模式工厂方法模式抽象工厂模式建造者模式原型模式的主要结构和关系。

特性 单例模式(Singleton) 简单工厂模式(Simple Factory) 工厂方法模式(Factory Method) 抽象工厂模式(Abstract Factory) 建造者模式(Builder) 原型模式(Prototype)
目的 确保一个类只有一个实例,并提供一个全局访问点。 通过工厂类创建不同类型的对象,封装对象的创建过程。 通过子类工厂创建不同类型的对象,实现工厂接口。 创建一系列相关或相互依赖的对象,确保它们能够协同工作。 分步构建复杂对象,使得同样的构建过程可以创建不同的表示。 通过复制现有对象创建新对象,避免重复的对象创建过程。
主要角色 单例类 工厂类、产品接口、具体产品类 抽象工厂类(Creator)、具体工厂类、产品接口、具体产品类 抽象工厂接口、具体工厂类、多个产品接口、具体产品类 产品、抽象建造者、具体建造者、指挥者 原型接口、具体原型类、客户端
实例数量控制 仅一个实例 不限制实例数量 不限制实例数量 不限制实例数量 不限制实例数量 不限制实例数量
创建过程 通过静态方法或懒加载确保唯一实例。 通过工厂类的静态方法根据参数创建不同产品。 通过具体工厂子类实现创建方法,实例化具体产品。 通过具体工厂创建一系列相关产品。 通过指挥者控制建造者逐步构建复杂对象。 通过原型接口复制现有对象。
扩展性 较低,无法灵活扩展。 不易扩展,新增产品需修改工厂类。 易扩展,新增具体工厂和产品类符合开闭原则。 非常高,新增产品族只需新增具体工厂和产品类。 易于扩展,新增建造者类可创建不同的对象表示。 易于扩展,通过新增原型类支持更多类型的对象复制。
灵活性 较低,唯一实例限制了灵活性。 中等,通过参数选择不同产品,但工厂类需要预先知道所有产品。 较高,通过子类工厂选择不同产品,符合多态性。 非常高,支持创建一系列相关产品,确保产品族的兼容性。 高,分步构建过程可灵活定制对象的各个部分。 高,支持动态复制不同类型的对象,灵活性强。
依赖关系 客户端依赖于单例类。 客户端依赖于工厂类和产品接口。 客户端依赖于抽象工厂接口和产品接口。 客户端依赖于抽象工厂接口和多个产品接口。 客户端依赖于建造者接口和指挥者。 客户端依赖于原型接口。
适用场景 全局资源控制,如配置管理、日志记录、数据库连接池。 对象创建过程简单,多种相似对象创建。 产品类较多或频繁变化,需要通过子类化管理不同产品。 需要创建一系列相关或相互依赖的对象,确保产品族兼容性。 创建复杂对象,分步骤构建,需灵活定制对象的内部组成。 需要频繁复制对象,或对象创建成本较高。

8.2. 灵活性与扩展性

  • 单例模式

    • 灵活性:较低,唯一实例限制了其灵活性。

    • 扩展性:低,不易扩展。

  • 简单工厂模式

    • 灵活性:中等,通过参数选择不同产品。

    • 扩展性:较低,新增产品需修改工厂类,违背开闭原则。

  • 工厂方法模式

    • 灵活性:较高,通过子类工厂选择不同产品。

    • 扩展性:高,符合开闭原则,易于扩展新产品。

  • 抽象工厂模式

    • 灵活性:非常高,支持创建一系列相关产品。

    • 扩展性:非常高,易于新增产品族,符合开闭原则。

  • 建造者模式

    • 灵活性:高,分步构建可灵活定制对象。

    • 扩展性:高,易于新增建造者类,支持不同的对象表示。

  • 原型模式

    • 灵活性:高,支持动态复制不同类型的对象。

    • 扩展性:高,通过新增原型类支持更多类型。

8.3. 适用场景

  • 单例模式

    • 全局资源控制:如配置管理、日志记录、数据库连接池等。

    • 需要唯一实例:避免资源冲突和重复实例化。

  • 简单工厂模式

    • 对象创建过程简单:如图形绘制应用、日志记录系统。

    • 需要创建多种相似对象:如交通工具管理系统。

  • 工厂方法模式

    • 产品类较多或频繁变化:如不同平台下的UI组件创建。

    • 需要通过子类化管理不同产品:如不同类型的文档生成器。

  • 抽象工厂模式

    • 需要创建一系列相关或相互依赖的对象:如跨平台UI组件。

    • 确保产品族的兼容性:如不同风格的家具套装。

  • 建造者模式

    • 创建复杂对象:如复杂的文档生成、复杂的用户界面组件。

    • 需要灵活定制对象的内部组成部分:如根据不同配置生成不同版本的产品。

  • 原型模式

    • 需要频繁复制对象:如游戏中的角色复制、大量相似配置文件的创建。

    • 对象创建成本较高:如复杂图形对象、复杂配置对象。

8.4. 优缺点对比

特性 单例模式(Singleton) 简单工厂模式(Simple Factory) 工厂方法模式(Factory Method) 抽象工厂模式(Abstract Factory) 建造者模式(Builder) 原型模式(Prototype)
优点 - 控制实例数量
- 提供全局访问点
- 封装对象创建过程
- 简化客户端代码
- 集中管理对象创建
- 符合开闭原则
- 符合开闭原则
- 封装对象创建
- 提高代码复用性和可维护性
- 创建一系列相关对象
- 符合开闭原则
- 封装具体类
- 增强系统灵活性和可扩展性
- 封装复杂构建过程
- 分离构建与表示
- 符合单一职责原则
- 易于扩展
- 支持流畅接口
- 提高性能
- 动态创建对象
- 隐藏复杂创建逻辑
- 支持多态复制
缺点 - 难以测试
- 隐藏依赖
- 并发问题
- 违反单一职责原则
- 增加系统复杂性
- 不易扩展
- 增加类的数量
- 结构复杂性
- 不适用于单一产品创建
- 增加类的数量
- 结构复杂性
- 不适用于单一产品创建
- 增加类的数量
- 代码复杂性
- 维护成本
- 实现复杂性
- 依赖具体原型
- 复制成本
- 难以维护
适用场景 - 全局资源控制
- 需要唯一实例
- 对象创建过程简单
- 创建多种相似对象
- 客户端不关心具体类
- 产品类较多或频繁变化
- 需要通过子类工厂创建不同产品
- 需要创建相关对象
- 确保产品族兼容性
- 独立于具体类创建
- 创建复杂对象
- 需要灵活定制对象内部组成
- 需要频繁复制对象
- 对象创建成本高

9. 选择合适的创建型模式

选择合适的创建型设计模式需要根据具体的需求、系统的复杂性以及产品类的数量和变化频率来决定。以下是一些选择指南:

9.1. 使用单例模式的情况

  • 全局资源控制:如配置管理、日志记录、数据库连接池等。

  • 需要唯一实例:确保系统中只有一个实例存在,避免资源冲突。

9.2. 使用简单工厂模式的情况

  • 对象创建过程相对简单:对象的创建逻辑不复杂,不需要创建多个相关对象。

  • 产品类较少且不易频繁变化:系统中产品类数量有限,且新增产品类的频率不高。

  • 客户端仅需通过参数决定创建哪一种产品:无需通过子类化来决定具体产品类。

9.3. 使用工厂方法模式的情况

  • 产品类较多或频繁变化:需要通过子类化管理不同产品类,便于扩展。

  • 符合开闭原则:希望通过新增子类来支持新的产品,而不修改已有代码。

  • 需要通过子类工厂创建不同产品:不同的工厂子类负责创建不同产品,实现职责分离。

9.4. 使用抽象工厂模式的情况

  • 需要创建一系列相关或相互依赖的对象:如跨平台UI组件,确保产品族的一致性。

  • 系统需要独立于具体产品类的创建:客户端只依赖于抽象工厂和抽象产品接口,减少对具体类的依赖。

  • 需要确保产品族的协同工作:通过同一个具体工厂创建的产品对象能够协同工作,符合设计的一致性。

9.5. 使用建造者模式的情况

  • 创建复杂对象:对象的创建涉及多个步骤或多个部分,如生成不同类型的文档、构建复杂的用户界面组件。

  • 需要灵活定制对象的内部组成部分:根据不同的需求定制对象的各个部分。

  • 希望通过不同的建造者创建不同的对象表示:如根据不同的配置生成不同的产品版本。

9.6. 使用原型模式的情况

  • 需要频繁复制对象:如游戏中的角色复制、大量相似配置文件的创建。

  • 对象的创建成本较高:如图形编辑器中的复杂图形对象、复杂配置对象。

  • 希望在运行时动态指定对象类型:通过复制不同的原型对象,可以在运行时灵活决定新对象的类型。

  • 实现对象的多态复制:需要根据上下文复制不同类型的对象,促进代码的多态性。


10. 总结

创建型设计模式通过不同的方式简化和优化对象的创建过程,降低系统的耦合度,提升代码的可维护性和扩展性。以下是对单例模式简单工厂模式工厂方法模式抽象工厂模式建造者模式原型模式的总结:

  • 单例模式

    • 特点:确保类的唯一实例,提供全局访问点。

    • 适用场景:全局资源控制、需要唯一实例。

    • 优缺点:控制实例数量、提供全局访问点;但难以测试、隐藏依赖、并发问题。

  • 简单工厂模式

    • 特点:集中管理对象创建,通过参数决定具体产品类。

    • 适用场景:对象创建过程简单、多种相似对象创建、客户端不关心具体类。

    • 优缺点:封装对象创建、简化客户端代码;但违反单一职责原则、增加系统复杂性、不易扩展。

  • 工厂方法模式

    • 特点:通过子类工厂决定具体产品类,实现工厂接口。

    • 适用场景:产品类较多或频繁变化、符合开闭原则、通过子类工厂创建不同产品。

    • 优缺点:符合开闭原则、封装对象创建、提高代码复用性;但增加类的数量、结构复杂性、不适用于单一产品创建。

  • 抽象工厂模式

    • 特点:创建一系列相关或相互依赖的对象,确保产品族的兼容性。

    • 适用场景:需要创建相关对象、确保产品族兼容性、独立于具体类创建。

    • 优缺点:创建相关对象、符合开闭原则、封装具体类、增强系统灵活性和可扩展性;但增加类的数量、结构复杂性、不适用于单一产品创建。

  • 建造者模式

    • 特点:分步构建复杂对象,使得同样的构建过程可以创建不同的表示。

    • 适用场景:创建复杂对象、需要灵活定制对象内部组成部分、希望通过不同建造者创建不同对象表示。

    • 优缺点:封装复杂构建过程、分离构建与表示、符合单一职责原则、易于扩展、支持流畅接口;但增加类的数量、代码复杂性、维护成本。

  • 原型模式

    • 特点:通过复制现有对象创建新对象,避免重复对象创建过程。

    • 适用场景:需要频繁复制对象、对象创建成本较高、希望动态指定对象类型、实现对象的多态复制。

    • 优缺点:提高性能、动态创建对象、隐藏复杂创建逻辑、支持多态复制;但实现复杂性、依赖具体原型、复制成本、难以维护。

选择合适的创建型模式应根据系统的具体需求、产品类的数量和变化频率以及系统的扩展性要求来决定。合理运用创建型设计模式,可以显著提升系统的设计质量和代码的可维护性。然而,过度使用设计模式可能导致系统复杂性增加,因此应根据实际情况合理应用。