我们已经完整的介绍了 5 种创建型模式,他们分别是单例(Singleton)模式、原型(Prototype)模式、建造者(Builder)模式、工厂方法(Factory Method)模式和抽象工厂(Abstract Factory)模式。正如他们所属的分类名称一样,这几个模式都与对象的创建密切相关,但他们之间仍然有较大的区别,这些区别可能来自于类图结构、目的和所强调的侧重点等方面。
上图为所有创建型模式的类图结构(简化版)汇总图。
在五种创建型模式中,单例模式太过特殊,它通常仅与自身有关,所以在相同点中我们不考虑单例模式。在剩下的创建型模式中,他们都在围绕着两个主题开展工作。一个主题是面向接口,一个主题是屏蔽产品构建细节。得益于这两个主题,使得系统具有极大的灵活性。从此以后,我们可以用结构或者功能差别非常大的不同的产品对象来配置化系统。这些配置可以发生在程序编译期间(静态配置),也可以发生程序的运行期间(动态配置)。
不论是工厂方法模式还是原型模式,亦或是抽象工厂模式,与客户端直接交互的是高层的抽象接口。用户只知道高层抽象的接口(例如工厂方法模式中Creator#create():Product
、抽象工厂模式中AbstractFactory#createProductA():ProductA
和AbstractFactory#createProductB():ProductB
、原型模式中Prototype#clone():Prototype
),并不需要关心所要创建的产品的具体类型。建造者模式也是如此,尽管建造者模式在抽象的建造器Builder
之上提供了可被复用的导向器Director
,但其并不影响客户端面向接口的本质,因为所建造产品的具体类型取决于建造器而非导向器。
创建型模式的另一个主题是屏蔽产品的构建细节,客户端并不知道产品是如何被构建出来的。对于工厂方法模式、原型模式和抽象工厂模式来说,客户端甚至不知道获取的产品的真实类型(返回的类型是抽象的Product
,而不是实际的ConcreteProduct
)。客户端并不知道产品对象的构建过程,被谁创建的以及何时被创建等一些细节。
总的来说,单例模式很容易和其他模式区分开来,它太过独立。原型模式、建造者模式、工厂方法模式和抽象工厂模式都与构建产品有关系,他们都拥有着创建产品的“工厂对象”。其中抽象工厂模式较为特殊,他的“工厂对象”通常用于创建一系列具有相关性的产品。原型模式通过克隆的方式得到了与自身类型相同的产品对象,原型模式的“工厂对象”就是原型对象自身。建造者模式通过“工厂对象”使用相对复杂的协议,逐步的完成一个产品的创建。同时工厂方法模式的“工厂对象”也负责创建并返回一个产品对象。
- 单例模式的结构极其特殊,它通常表现为独立的类,所以单例模式很容易区分;
- 原型模式也较为容易区分,原型对象通过克隆自身的行为来构建新的产品对象,产品对象和原型对象都属于同一个类的实例;
- 抽象工厂模式的结构也很容易区分,抽象工厂的结构看起来要更加复杂,因为抽象工厂包含了多个产品维度;
- 建造者模式和工厂方法模式有相似性,他们的结构中都包含了三个组成部分:产品对象、制造产品的接口_和_制造产品的具体对象。通常情况下,建造者模式比工厂方法模式多一个导向器(
Director
)的角色。并且,工厂方法模式需要为一个产品配备一个相应的工厂,而建造者模式却没有这样的约束,建造者模式甚至不要求产品进行抽象。
- 单例模式的目的是为了保证一个类有且只有一个实例,可以通过全局访问点来访问对象。保证一个实例的原因可能是多种多样的,但无论哪种场景,想要保证一个类只有一个实例都可以用单例模式;
- 原型模式的目的是为了对象复制,强调从一个对象中复制出另一个对象来,这两个对象是同一个类的实例,甚至有可能这两个对象是同一个对象;
- 建造者模式强调对于复杂对象的构建,如果一个对象很简单,使用建造者模式往往适得其反。建造者模式将对象的构建过程和对象的表示分离开来(因为复杂对象的构建过程相当麻烦,和对象的表示放在一起看起来比较混乱),并且建造者模式期望通过完全一样的步骤来创建不同的产品;
- 工厂方法模式则是将产品的生产交给子类,强调由子类决定实例化哪一个具体的产品;
- 抽象工厂模式强调的是一些列相关产品对象的创建,抽象工厂模式将产生多个类的对象。
在所有创建型模式中,建造者模式和工厂方法模式更为相似,关于他们的更深层次的区分主要有如下几点。
- 建造者模式的目的是为了构建一个复杂的对象,如果一个对象很简单,则不应该使用建造者模式。他将一个对象的构建步骤零散化,将一个复杂的操作拆分成多个简单的环节,并且这些细小的环节可以被缺省。而工厂方法模式则并不要求构建对象的复杂性,如果一个产品的构建过程需要配置太多的状态,使用工厂方法模式并不是好的选择;
- 并且,建造者生产出来的产品理论上可以是任意类型的,尽管有些产品不需要其中的一些步骤,建造者模式的客户端能清楚的获取到产品的真实类型。而工厂方法模式创建的产品都继承自一个抽象的产品类,客户端并不知道创建出来的产品的真实类型;
- 除此之外,建造者模式更多的时候需要一个导向器(
Director
),导向器负责控制各个步骤的先后顺序,同时也可以用来方便复用。但工厂方法模式显然不需要,因为它并不关心产品构建的步骤,它只要求提供给客户端一个产品对象即可。