目录¶
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. 优缺点¶
优点:
控制实例数量:确保系统中只有一个实例,节约资源。
全局访问点:提供全局访问点,方便在任何地方使用。
缺点:
难以测试:单例的全局状态可能导致测试变得困难。
隐藏依赖:通过全局访问点引入依赖,降低代码的透明度。
并发问题:在多线程环境下,需额外处理同步问题,防止多实例创建。
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. 优缺点¶
优点:
封装对象创建:集中管理对象创建过程,客户端无需了解具体类的创建细节。
简化客户端代码:客户端通过工厂方法获取对象,减少了直接实例化的代码量。
集中管理对象创建:所有对象的创建由工厂类统一管理,便于维护和扩展。
符合开闭原则:通过修改工厂类,可以增加新产品的支持,而无需修改客户端代码。
缺点:
违反单一职责原则:工厂类承担了创建所有产品的职责,可能导致工厂类过于庞大。
增加系统复杂性:每增加一种产品类型,都需要修改工厂类,增加了工厂类的复杂性。
不易扩展:对于产品种类频繁变化的系统,简单工厂模式可能不够灵活,难以适应需求变化。
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. 优缺点¶
优点:
符合开闭原则:通过引入新的具体工厂和产品类,可以扩展系统功能,而无需修改已有代码。
封装对象创建:将对象的创建过程封装在具体工厂类中,客户端无需了解具体类的创建细节。
提高代码复用性和可维护性:不同的具体工厂类可以复用相同的创建逻辑,便于维护和管理。
缺点:
增加类的数量:每种产品类型都需要对应一个具体工厂类,可能导致类的数量增加。
结构复杂性:相对于简单工厂模式,工厂方法模式的结构更加复杂,需要定义抽象工厂接口和具体工厂类。
不适用于单一产品的创建:当产品种类较少且不易扩展时,工厂方法模式可能显得过于繁琐。
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. 优缺点¶
优点:
创建一系列相关对象:通过一个工厂接口,可以创建一系列相关或相互依赖的对象,确保产品族的兼容性。
符合开闭原则:通过新增具体工厂和产品类,可以扩展系统功能,而无需修改已有代码。
封装具体类:客户端无需了解具体产品类的实现,降低了系统的耦合度。
增强系统的灵活性和可扩展性:不同的工厂可以创建不同的产品族,适应多变的需求。
缺点:
增加类的数量:每增加一个产品族,都需要新增一个具体工厂类和相应的具体产品类,可能导致类的数量迅速增加。
结构复杂性:结构相对复杂,需要定义抽象工厂接口和多个具体工厂类,增加了系统的复杂性。
不适用于单一产品的创建:如果系统只需要创建单一类型的产品,抽象工厂模式可能显得过于复杂。
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. 优缺点¶
优点:
封装复杂的构建过程:将复杂对象的构建过程封装在建造者中,简化客户端代码。
分离构建与表示:允许同样的构建过程创建不同的表示,增强系统的灵活性。
符合单一职责原则:建造者专注于产品的构建,不涉及产品的表示或其他业务逻辑。
易于扩展:通过新增具体建造者,可以轻松扩展系统功能,而无需修改已有代码。
支持流畅接口:建造者模式可以与流畅接口结合,实现链式调用,提升代码的可读性。
缺点:
增加类的数量:每个具体建造者需要创建一个新的建造者类,可能导致系统中类的数量增加。
代码复杂性:对于简单的对象创建,使用建造者模式可能显得过于复杂。
维护成本:随着产品的复杂性增加,建造者类的实现和维护可能变得更加繁琐。
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. 优缺点¶
优点:
提高性能:通过复制现有对象创建新对象,避免了重复的初始化过程,尤其在对象创建成本较高时显著提升性能。
动态创建对象:允许在运行时动态地选择和复制不同的原型对象,增强系统的灵活性。
隐藏复杂创建逻辑:客户端无需了解对象的创建细节,只需复制原型即可获得新对象。
支持多态复制:通过抽象原型接口,支持不同类型的原型对象被统一复制,促进代码的多态性。
缺点:
实现复杂性:需要确保所有原型对象都实现了正确的复制方法,特别是在涉及深拷贝和浅拷贝时。
依赖具体原型:客户端需要了解可用的原型对象,可能导致对具体原型的依赖。
复制成本:对于某些复杂对象,复制过程本身可能具有一定的开销,尤其是深拷贝操作。
难以维护:随着系统中原型对象的增多,管理和维护这些原型对象可能变得复杂。
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. 总结¶
创建型设计模式通过不同的方式简化和优化对象的创建过程,降低系统的耦合度,提升代码的可维护性和扩展性。以下是对单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式的总结:
单例模式:
特点:确保类的唯一实例,提供全局访问点。
适用场景:全局资源控制、需要唯一实例。
优缺点:控制实例数量、提供全局访问点;但难以测试、隐藏依赖、并发问题。
简单工厂模式:
特点:集中管理对象创建,通过参数决定具体产品类。
适用场景:对象创建过程简单、多种相似对象创建、客户端不关心具体类。
优缺点:封装对象创建、简化客户端代码;但违反单一职责原则、增加系统复杂性、不易扩展。
工厂方法模式:
特点:通过子类工厂决定具体产品类,实现工厂接口。
适用场景:产品类较多或频繁变化、符合开闭原则、通过子类工厂创建不同产品。
优缺点:符合开闭原则、封装对象创建、提高代码复用性;但增加类的数量、结构复杂性、不适用于单一产品创建。
抽象工厂模式:
特点:创建一系列相关或相互依赖的对象,确保产品族的兼容性。
适用场景:需要创建相关对象、确保产品族兼容性、独立于具体类创建。
优缺点:创建相关对象、符合开闭原则、封装具体类、增强系统灵活性和可扩展性;但增加类的数量、结构复杂性、不适用于单一产品创建。
建造者模式:
特点:分步构建复杂对象,使得同样的构建过程可以创建不同的表示。
适用场景:创建复杂对象、需要灵活定制对象内部组成部分、希望通过不同建造者创建不同对象表示。
优缺点:封装复杂构建过程、分离构建与表示、符合单一职责原则、易于扩展、支持流畅接口;但增加类的数量、代码复杂性、维护成本。
原型模式:
特点:通过复制现有对象创建新对象,避免重复对象创建过程。
适用场景:需要频繁复制对象、对象创建成本较高、希望动态指定对象类型、实现对象的多态复制。
优缺点:提高性能、动态创建对象、隐藏复杂创建逻辑、支持多态复制;但实现复杂性、依赖具体原型、复制成本、难以维护。
选择合适的创建型模式应根据系统的具体需求、产品类的数量和变化频率以及系统的扩展性要求来决定。合理运用创建型设计模式,可以显著提升系统的设计质量和代码的可维护性。然而,过度使用设计模式可能导致系统复杂性增加,因此应根据实际情况合理应用。