工厂模式:设计模式系列(二)
工厂模式(Factory Pattern):是定义一个用于创建对象的接口,但不指定其具体类,在需要创建实例的时候再由需求来决定的设计模式,归类为创建型模式。
这一模式根据层次分类,可以分为以下几种:
- 简单工厂模式(Simple Factory Pattern)
- 工厂方法模式(Factory Method Pattern)
- 抽象工厂模式(Abstract Factory Pattern)
这几种细分模式本质其实就是抽象,理解好他们的本质,就能很好地在使用这些模式的时候自由切换,而这写模式也体现了LSP、DIP、和ISP。
简单工厂模式(Simple Factory Pattern):专门定义一个类来实例化其它类,被创建的实例通常都具有共同的父类或接口。这一模式建立思考过程相对简单,按照以下步骤进行:
- 现在需要几种对象,这些对象抽象出来的本质一样,可以把抽象出来后相同的属性和功能建立一个接口或协议。
- 但这些对象具体实例又具备细微的差异,可以通过已经建立了的接口或协议建立对应的实现类,由这些实现类进行适当的扩展。
- 由于这些实例对象都需要被调用,但逐个创建很麻烦,所以就创建一个工厂类,专门用来创建上面这些本质一样的实例对象。
可以发现,简单工厂模式结构包含3个部分,接口或协议、具体实现类、可以创建其它类实例的类。
简单工厂模式示例代码如下(Swift语言):
protocol ObjectBluePrint{
func show();
}
class Object1: ObjectBluePrint{
func show() {
print("Show object1");
}
}
class Object2: ObjectBluePrint{
func show() {
print("Show object2");
}
}
class Factory{
func createObject(name:String)->ObjectBluePrint?{
switch(name){
case ("object1"):
return Object1();
case ("object2"):
return Object2();
default:
return nil;
}
}
}
var factory = Factory();
var o1:ObjectBluePrint = factory.createObject("object1")!;
o1.show();
var o2:ObjectBluePrint = factory.createObject("object2")!;
o2.show();
代码分析:ObjectBluePrint
是一个协议,用于表示多种对象的本质,也就是各种实现类都应该具备的功能,这里写了2个实现类,Object1
和Object2
,他们之间有细微的区别,而在下面,有一个Factory
的实现类,类中方法createObject
能基于ObjectBluePrint
创建具体需要的实例对象,上面的代码中输出结果如下:
Show object1
Show object2
工厂方法模式(Factory Method Pattern):则是在简单工厂模式之上,把工厂抽象化,使工厂类分为接口或协议、具体实现两部分,可以想象,这么做的原因是工厂有可能有很多个,而多个工厂之间也有细微的区别。这时候,建立思考过程在简单工厂模式上进行一点的添加修改即可:
- 现在需要几种对象,这些对象抽象出来的本质一样,可以把抽象出来后相同的属性和功能建立一个接口或协议。
- 但这些对象具体实例又具备细微的差异,可以通过已经建立了的接口或协议建立对应的实现类,由这些实现类进行适当的扩展。
- 由于这些实例对象都需要被调用,但逐个创建很麻烦,于是需要创建工厂类来进行创建,但是同一工厂创建出来的对象是一样的,为了创建出具有各自工厂特色的对象,需要把工厂抽象出来建立一个代表本质的接口或协议。
- 那么现在有了工厂的本质了,就需要把工厂实例化,最终达到创建实例对象的目的。
可以发现,相对于简单工厂模式,工厂方法模式多了一个部分,对象的接口或协议、对象的实现类、工厂的接口或协议、工厂的实现类。
工厂方法模式示例代码如下(Swift语言):
protocol ObjectBluePrint{
func show();
}
class Object1: ObjectBluePrint{
func show() {
print("Show object1");
}
}
class Object2: ObjectBluePrint{
func show() {
print("Show object2");
}
}
class Object3: ObjectBluePrint{
func show() {
print("Show object3");
}
}
class Object4: ObjectBluePrint{
func show() {
print("Show object4");
}
}
protocol FactoryBluePrint{
func createObject(name:String)->ObjectBluePrint?;
}
class Factory1: FactoryBluePrint{
func createObject(name:String)->ObjectBluePrint?{
switch(name){
case ("object1"):
return Object1();
case ("object2"):
return Object2();
default:
return nil;
}
}
}
class Factory2: FactoryBluePrint{
func createObject(name:String)->ObjectBluePrint?{
switch(name){
case ("object3"):
return Object3();
case ("object4"):
return Object4();
default:
return nil;
}
}
}
var factory1:FactoryBluePrint = Factory1();
var o1:ObjectBluePrint = factory1.createObject("object1")!;
o1.show();
var o2:ObjectBluePrint = factory1.createObject("object2")!;
o2.show();
var factory2:FactoryBluePrint = Factory2();
var o3:ObjectBluePrint = factory2.createObject("object3")!;
o3.show();
var o4:ObjectBluePrint = factory2.createObject("object4")!;
o4.show();
代码分析:可以发现,上面的代码是基于简单工厂模式,添加了FactoryBluePrint
协议,为了显示出区别把Factory实现类分为Factory1
和Factory2
,这时因为两个工厂的不一样,所以可以根据各自工厂的特色创建对象了,上面的代码中输出结果如下:
Show object1
Show object2
Show object3
Show object4
抽象工厂模式(Abstract Factory Pattern):抽象工厂模式是工厂方法模式在创建对象结构方面的升级,可以从工厂方法模式中看到,所有创建的对象都具有同一接口或协议(可以理解为对象具有同一本质),而在抽象工厂模式中,工厂将要创建的对象具有不一样的接口和协议(理解为对象本质不一样),这时候,建立思考过程在工厂方法模式上进行一点的添加修改即可:
- 现在需要几种对象,这些对象抽象出来的本质不一样,可以把抽象出来后相同的属性和功能建立一个接口或协议,而不一样的属性和功能建立另一个接口或协议。
- 在这些对象中具体实例又具备细微的差异,可以通过已经建立了的接口或协议建立对应的实现类,由这些实现类进行适当的扩展。
- 由于这些实例对象都需要被调用,但逐个创建很麻烦,于是需要创建工厂类来进行创建,但是同一工厂创建出来的对象是一样的,为了创建出具有各自工厂特色的对象,需要把工厂抽象出来建立一个代表本质的接口或协议。
- 那么现在有了工厂的本质了,就需要把工厂实例化,最终达到创建实例对象的目的。
可以发现,抽象工厂模式跟工厂方法模式具有一样的分类,对象的接口或协议、对象的实现类、工厂的接口或协议、工厂的实现类,不同之处在于对象的接口或协议是多个的而非一个。
抽象工厂模式示例代码如下(Swift语言):
protocol ObjectBluePrint1{
func show();
}
class Object1: ObjectBluePrint1{
func show() {
print("Show object1");
}
}
class Object2: ObjectBluePrint1{
func show() {
print("Show object2");
}
}
protocol ObjectBluePrint2{
func tell();
}
class Object3: ObjectBluePrint2{
func tell() {
print("tell object3");
}
}
class Object4: ObjectBluePrint2{
func tell() {
print("tell object4");
}
}
protocol FactoryBluePrint{
func createObject(name:String)->ObjectBluePrint1?;
func createObject(name:String)->ObjectBluePrint2?;
}
class Factory1: FactoryBluePrint{
func createObject(name:String)->ObjectBluePrint1?{
switch(name){
case ("object1"):
return Object1();
default:
return nil;
}
}
func createObject(name:String)->ObjectBluePrint2?{
switch(name){
case ("object3"):
return Object3();
default:
return nil;
}
}
}
class Factory2: FactoryBluePrint{
func createObject(name:String)->ObjectBluePrint1?{
switch(name){
case ("object2"):
return Object2();
default:
return nil;
}
}
func createObject(name:String)->ObjectBluePrint2?{
switch(name){
case ("object4"):
return Object4();
default:
return nil;
}
}
}
var factory1:FactoryBluePrint = Factory1();
var o1:ObjectBluePrint1 = factory1.createObject("object1")!;
o1.show();
var o3:ObjectBluePrint2 = factory1.createObject("object3")!;
o3.tell();
var factory2:FactoryBluePrint = Factory2();
var o2:ObjectBluePrint1 = factory2.createObject("object2")!;
o2.show();
var o4:ObjectBluePrint2 = factory2.createObject("object4")!;
o4.tell();
代码分析:可以发现,上面的代码是基于工厂方法模式,修改了ObjectBluePrint
协议为ObjectBluePrint1
,增加了ObjectBluePrint2
,并且在FactoryBluePrint
中区分了创建对象的类型,为了显示出区别把Factory实现类中创建对象的方法重载,这样就能看出多种对象接口或协议对应的对象被创建出来的区别了,上面的代码中输出结果如下:
Show object1
tell object3
Show object2
tell object4
总结:工厂模式是非常常用的一种设计模式,也很严格地遵循和体现了LSP、DIP,对于降低耦合作用很大。重点在于对工厂和创建对象的本质的抽象,而难点则是在持续对模式相关代码的扩展中,理解好本质,在使用的时候会发现这其实能一定程度上提升开发效率。