《设计模式》-03-GoF模式-创建型模式(单例模式、原型模式、构造器模式、抽象工厂模式、工厂方法模式)
文章目录
1. 单例模式(Singleton)
指目标类(Class)只有一个实例对象(Object),并且向使用该对象的客户端提供访问单例的全局方法。
1.1 使用场景
- 一个类只能有一个实例,并且客户端需要访问该实例。
例如,将软件配置信息封装在一个类中,这个类的实例需要向所有客户端提供一致的配置信息。
- 一个类的实例化代价很大,且向所有客户端提供无状态的服务(实例状态在程序中通常使用变量或域表达)或不因客户端变化而改变实例状态的服务。
1.2 类结构
Subject定义了静态私有域instance、私有无参构造方法和全局静态方法getInstance(),当客户端通过getInstance()方法访问私有域instance时,判断instance是否为null;如果为null,则通过私有构造方法初始化instance;最后向客户端返回instance。
1.3 使用单例
COS系统的配置信息使用XML格式文件保存。COS启动后,需要向所有客户端(Client)程序共享该配置信息,并提供配置信息访问的接口。
2 原型模式(Prototype)
指通过复制自己达到构造目标对象新实例的对象。
2.1 应用场景
原型解决的问题是减少了设计中存在大量的相似类(也称平行类)或子类,可以实现动态地配置应用或动态地添加和删除产品,通过复制对象的方式提高了某一类型对象的创建性能。
其应用场景如下:
- 一个类的实例状态只能是不同组合中的一种,而不想通过平行类或子类的方式区分不同的状态组合。
该场景,客户端使用目标类的实例时,需要根据实例状态的变化实现不同的服务类型,开发人员可以通过子类扩展或设计平行类的方式解决,但这样会增加设计类的数量。特别地,当目标类实例的状态组合较多时,将导致类爆炸。采用原型模式设计方案,可以减少子类或平行类的数量,从而避免类爆炸问题。
- 业务代码中不能静态引用目标类的构造器来创建新的目标类的实例。
客户端无法直接通过构造器创建新的目标对象;需要向客户端提供目标类原型对象,通过原型复制的方式创建新的实例。如:
为了安全,客户端没有权限直接引用目标类的构造器构造实例;或者系统为了方便资源管理,希望通过复制原型的方式保留新对象与原型对象之间的某种联系。
- 目标类实例化代价昂贵(通常指初始化含有耗时或较高计算复杂度的操作),不同的客户端需要单独使用一个目标类的对象。
原型复制的方式在某些情况下可以提高程序的性能。
因为系统在创建新对象时不需要进行对象模型的计算与构建,而是直接制作对象的副本,也没有对象初始化过程,这在一定程度上节省了新对象创建的成本,起到了程序优化的效果。
2.2 类结构
客户端Client通过原型Prototype对象的clone()方法获得新的目标实例。Prototype可以设计为抽象类或接口,由子类实现clone()方法,也可以设计为具体类。
2.3 使用原型
如订单通知、系统通知、会员通知等。
3 构造器模式(Builder)
指为构造一个复杂的产品对象 进行产品组成元素构建和产品组装的对象。构造器模式将产品构造过程(或算法)进行独立封装。
3.1 应用场景
- 需要将复杂产品对象的构造过程(或算法)封装在独立的代码中。
例如,为了实现产品构造过程(或算法)的可扩展性或复用性需要将产品组合元素的构造、产品构造过程(或算法)及产品的组装等分别由独立的对象封装。
- 对不同的产品表示复用同一个构造过程(或算法)。
如,代码需要创建不同的产品表示,但这些产品的构造过程(或算法)相似或相同,可以进行构造过程(或算法)代码的复用。
3.2 结构类
- Director类,封装产品构造过程(或算法)
- Builder接口,定义产品聚合元素的构建行为
- ConcreteBuilder,实现Builder接口和具体产品的组装
- Product,是产品的具体表示(或类型)
Director实现的产品构造过程(或算法)中使用Builder类型对象构造产品的聚合元素,由于Builder是抽象接口类型,因此,同一个Director的产品构造过程(或算法)可以构造出不同的产品表示,从而达到代码复用或扩展的目的。
4 抽象工厂模式(Abstract Factory)
指在不指定具体产品类的情况下,为相互关联的产品簇或产品集(Families of Products)提供创建接口,并向客户端隐藏具体产品创建的细节或表示的对象。
4.1 使用场景
- 需要实现产品簇样式的可扩展性,并向客户端隐藏具体样式产品簇的创建或表示细节
当产品簇中的产品类型具有不同的子类,而客户端在使用产品簇时,并不关心产品的具体子类,只是使用产品对象。为了减少客户端代码对产品簇具体实现的依赖,需要隐藏具体的产品表示和创建过程。
- 向客户端保证产品簇对象的一致性,但只提供产品对象创建接口
客户端在使用产品簇的产品对象时,对产品对象有一致性体验需求,主要体现在外观、样式、行为等
- 使用产品簇实现软件的可配置性。
主要针对于软件配置。
例如,SDK是开发人员所使用的产品簇,由能帮助开发人员进行软件开发的工具、程序库和文档组成,开发人员在开发目标软件时,需要配置对应的SDK产品簇。
4.2 类结构
产品簇中含有产品类型ProductA和ProductB,产品簇有样式1和样式2两种不同的样式,因此,ProductA有样式1的子类ProductA1和样式2的子类ProductA2,ProductB有样式1的子类ProductB1和样式2的子类ProductB2,即ProductA1与ProductB1构成样式1产品簇,ProductA2与ProductB2构成样式2产品簇。
客户端Client在使用产品簇时,需要保证产品样式的一致性,即客户端使用样式1产品簇时,需要抽象工厂创建和提供ProductA1或ProductB1产品对象;使用样式2产品簇时,需要抽象工厂创建和提供ProductA2或ProductB2产品对象。
抽象工厂类AbstractFactory定义产品簇中产品对象的创建接口createProductA()和createProductB()。ConcreteFactory1子类继承AbstractFactory类,实现样式1产品簇产品对象的创建;ConcreteFactory2子类继承AbstractFactory类,实现样式2产品簇产品对象的创建。
5 工厂方法模式(Factory Method)
工厂方法类定义产品对象创建接口,但由子类实现具体产品对象的创建。
5.1 使用场景
- 当业务类处理产品对象时,无法知道产品对象的具体类型,或不需要知道产品对象的具体类型(产品具有不同的子类)。
- 当业务类处理不同的产品子类对象业务时,希望由自己的子类实现产品子类对象的创建。
5.2 结构类
Creator类定义了抽象工厂方法createProduct(),实现了业务处理方法doBusiness()。
ConcreteCreator类继承Creator类,实现工厂方法createProduct()进行ConcreteProduct对象的创建。Product是产品抽象类,ConcreteProduct类继承Product类,是Product的子类。
客户端(Client)使用Creator对象对目标产品Product对象进行业务处理时,Product对象的创建是由ConcreteCreator类完成的。实际上,客户类使用的Creator对象指向的是ConcreteCreator实例。