1. 什么是工厂模式
工厂模式(Factory pattern)在设计模式中属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象
2. 工厂模式分类
工厂模式一般可以分为三类:
- 简单工厂模式(Simple Factory Pattern)
- 工厂方法模式(Factory Method Pattern)
- 抽象工厂模式(Abstract Factory Pattern)
接下来我们分别对这三个模式进行说明。
2.1 简单工厂模式
简单工厂模式又称作静态工厂方法模式,简单工厂模式专门定义一个工厂类来负责创建其他类的实例,且被创建的实例通常都具有共同的父类。它虽然不属于设计模式中的一种,但是在应用中依然很常见。
2.1.1 主要角色与关系
主要由三个角色组成:
- 工厂类(Factory):简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。
- 抽象产品类(AbstractProduct):简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
-
具体产品类(Product):是简单工厂模式的创建实体类。
2.1.2 代码实现
我们以生产电脑为例,假设有一个代工厂,它既可以生产苹果电脑,也可以生产小米电脑,这时候如果需要生产其中任意一种电脑,就直接找代工厂就行了。
- 创建一个产品抽象类Computer,定义好基础方法
// Computer.h
#import <Foundation/Foundation.h>
@interface Computer : NSObject
- (NSString *)productName;
@end
// Computer.m
#import "Computer.h"
@implementation Computer
- (NSString *)productName {
NSAssert(false, @"must implement in subClass");
return nil;
}
@end
- 创建产品具体类
2.1 mac电脑类
// Mac.h
#import "Computer.h"
@interface Mac : Computer
@end
// Mac.m
#import "Mac.h"
@implementation Mac
- (NSString *)productName {
return @"Mac";
}
@end
2.2 创建小米电脑类
// XiaoMi.h
#import "Computer.h"
@interface XiaoMi : Computer
@end
// XiaoMi.m
#import "XiaoMi.h"
@implementation XiaoMi
- (NSString *)productName {
return @"XiaoMi";
}
@end
- 产品都已经定义好了,接下来我们需要定义一个工厂类,装门从事生产这些商品
// ComputerSimpleFactory.h
#import <Foundation/Foundation.h>
#import "Mac.h"
#import "XiaoMi.h"
@interface ComputerSimpleFactory : NSObject
+ (Computer *)createComputerWithType:(NSInteger)type;
@end
// ComputerSimpleFactory.m
#import "ComputerSimpleFactory.h"
@implementation ComputerSimpleFactory
+ (Computer *)createComputerWithType:(NSInteger)type {
switch (type) {
case 1: {
//do something for create
Mac *computer = [[Mac alloc] init];
return computer;
}
break;
case 2: {
//do something for create
XiaoMi *computer = [[XiaoMi alloc] init];
return computer;
}
default:
break;
}
return nil;
}
@end
- 调用测试
+ (void)test1 {
Computer *macComputer = [ComputerSimpleFactory createComputerWithType:1];
NSLog(@"computer name = %@", macComputer.productName);
Computer *xmComputer = [ComputerSimpleFactory createComputerWithType:2];
NSLog(@"computer name = %@", xmComputer.productName);
}
2.1.3 分析
- 可以看出通过工厂类对产品创建进行了封装,使调用者不需要知道创建的具体逻辑,只需要调用工厂方法,即可得到相应的实例。一旦产品创建逻辑需要修改,也只需要修改工厂类即可,不必全局修改创建逻辑。
- 系统扩展困难,一旦添加新产品就不得不修改工厂类创建方法逻辑,破坏了“开闭原则”。在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
2.1.4 适用范围
- 适用于一些创建实例逻辑较为复杂,创建类型固定且被创建的类一般属于同一父类的情况。
2.2 工厂方法模式
工厂方法模式,又称工厂模式、多态工厂模式和虚拟构造器模式。
Define an interface for creating an object,but let subclasses decide which class toinstantiate.Factory Method lets a class defer instantiation to subclasses.
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
这满足创建型模式中所要求的“创建与使用相分离”的特点。同时改进了简单工厂模式中不易拓展的问题。
2.2.1 主要角色与关系
主要角色组成:
- 抽象工厂(AbstractFactory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
- 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
- 抽象产品(AbstractProduct):定义了产品的规范,描述了产品的主要特性和功能。
-
具体产品(Product):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
2.2.2 代码实现
我们依然以生产电脑为例,为了保持生产质量,一个工厂我们只让他负责生产一种电脑,苹果电脑生产就交给苹果电脑工厂,小米电脑生产就交给小米电脑工厂。
- 创建和定义抽象产品Computer和具体产品Mac、XiaoMi。这里产品类和前面一致,不再重复阐述。
- 定义工厂抽象类ComputerMethodFactory
// ComputerMethodFactory.h
#import <Foundation/Foundation.h>
#import "Computer.h"
@interface ComputerMethodFactory : NSObject
+ (Computer *)createComputer;
@end
// ComputerMethodFactory.m
#import "ComputerMethodFactory.h"
@implementation ComputerMethodFactory
+ (Computer *)createComputer {
NSAssert(false, @"must implement ins subClass");
return nil;
}
@end
- 定义具体工厂类
定义苹果电脑工厂类 MacComputerFactory
定义小米电脑工厂类 XiaoMiComputerFactory
// MacComputerFactory.h
#import "ComputerMethodFactory.h"
@interface MacComputerFactory : ComputerMethodFactory
@end
// MacComputerFactory.h
#import "MacComputerFactory.h"
#import "Mac.h"
@implementation MacComputerFactory
+ (Computer *)createComputer {
//do something for create
Mac *macComputer = [[Mac alloc] init];
return macComputer;
}
@end
// XiaoMiComputerFactory.h
#import "ComputerMethodFactory.h"
@interface XiaoMiComputerFactory : ComputerMethodFactory
@end
// XiaoMiComputerFactory.m
#import "XiaoMiComputerFactory.h"
#import "XiaoMi.h"
@implementation XiaoMiComputerFactory
+ (Computer *)createComputer {
//do something for create
XiaoMi *xmComputer = [[XiaoMi alloc] init];
return xmComputer;
}
@end
- 接下来进行简单的调用测试
//工厂方法模式测试
+ (void)test2 {
Computer *macComputer = [MacComputerFactory createComputer];
NSLog(@"computer name = %@", macComputer.productName);
Computer *xmComputer = [XiaoMiComputerFactory createComputer];
NSLog(@"computer name = %@", xmComputer.productName);
}
2.2.3 分析
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
- 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;
- 高层模块值需要知道产品的抽象类,其他的实现类都不用关心,符合迪米特法则,我不需要的就不要去交流;也符合依赖倒置原则,只依赖产品类的抽象;当然也符合里氏替换原则.
- 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度
2.2.4 适用范围
- 工厂方法模式在所有需要生成对象的地方都可以使用,但是需要慎重地考虑是否要增加一个工厂类进行管理,增加代码的复杂度。
- 需要灵活的、可扩展的框架时,可以考虑采用工厂方法模式,如:产品种类未来仍然可能保持新增的情况
2.3 抽象工厂模式
抽象工厂模式
Provide an interface for creating families of related or dependent objects withoutspecifying their concrete classes
为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品,可以生产一个产品族的产品。
2.3.1 主要角色与关系
主要由以下角色组成:
- 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
- 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
-
具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它 同具体工厂之间是多对一的关系。
2.3.2 代码实现
我们以前面工厂方法的例子的基础上进行举例说明。现在我们希望工厂在原来生产电脑的基础上,同时支持生产手机。这个时候我们就需要首先先取得生产许可(在抽象工厂类上赋予生产电脑和手机的能力),然后在具体工厂类进行生产,苹果工厂类负责生产苹果手机和苹果电脑,小米工厂则负责生产小米手机和小米电脑。
- 创建和定义抽象产品Computer和具体产品Mac、XiaoMi。这里产品类和前面一致,不再重复阐述。
- 创建和定义新的抽象产品Phone和具体产品类iPhone 和XiaoMiPhone
// Phone.h
#import <Foundation/Foundation.h>
@interface Phone : NSObject
- (NSString *)productName;
@end
// phone.m
#import "Phone.h"
@implementation Phone
- (NSString *)productName {
NSAssert(false, @"must implement in subClass");
return nil;
}
@end
// iPhone.m
#import "Phone.h"
@interface iPhone : Phone
@end
// iPhone.m
#import "iPhone.h"
@implementation iPhone
- (NSString *)productName {
return @"iphone";
}
@end
// XiaoMiPhone.h
#import "Phone.h"
@interface XiaoMiPhone : Phone
@end
// XiaoMiPhone.m
#import "XiaoMiPhone.h"
@implementation XiaoMiPhone
- (NSString *)productName {
return @"XiaoMiPhone";
}
@end
- 创建和定义抽象工厂类 ElectronAbstractFactory,定义生产手机和电脑功能
// ElectronAbstractFactory
#import <Foundation/Foundation.h>
#import "Phone.h"
#import "Computer.h"
@protocol ElectronAbstractFactoryInterface <NSObject>
@required
+ (Phone *)createPhone;
+ (Computer *)createComputer;
@end
@interface ElectronAbstractFactory : NSObject<ElectronAbstractFactoryInterface>
@end
// ElectronAbstractFactory.m
#import "ElectronAbstractFactory.h"
@implementation ElectronAbstractFactory
+ (Phone *)createPhone {
NSAssert(false, @"must implement in subClass");
return nil;
}
+ (Computer *)createComputer {
NSAssert(false, @"must implement in subClass");
return nil;
}
@end
- 定义具体工厂类AppleElectronFactory和XiaoMiElectronFactory
// AppleElectronFactory.h
#import "ElectronAbstractFactory.h"
@interface AppleElectronFactory : ElectronAbstractFactory
@end
// AppleElectronFactory.m
#import "AppleElectronFactory.h"
#import "iPhone.h"
#import "Mac.h"
@implementation AppleElectronFactory
+ (Computer *)createComputer {
//do something for create
Mac *mac = [[Mac alloc] init];
return mac;
}
+ (Phone *)createPhone {
//do something for create
iPhone *iphone = [[iPhone alloc] init];
return iphone;
}
@end
// XiaoMiElectronFactory.h
#import "ElectronAbstractFactory.h"
@interface XiaoMiElectronFactory : ElectronAbstractFactory
@end
// XiaoMiElectronFactory.m
#import "XiaoMiElectronFactory.h"
#import "XiaoMiPhone.h"
#import "XiaoMi.h"
@implementation XiaoMiElectronFactory
+ (Computer *)createComputer {
//do something for create
XiaoMi *mac = [[XiaoMi alloc] init];
return mac;
}
+ (Phone *)createPhone {
//do something for create
XiaoMiPhone *iphone = [[XiaoMiPhone alloc] init];
return iphone;
}
@end
- 进行调用测试对应代码
+ (void)test3 {
Computer *macComputer = [AppleElectronFactory createComputer];
NSLog(@"computer name = %@", macComputer.productName);
Phone *iphone = [AppleElectronFactory createPhone];
NSLog(@"computer name = %@", [iphone productName]);
Computer *xmComputer = [XiaoMiComputerFactory createComputer];
NSLog(@"computer name = %@", xmComputer.productName);
Phone *xiaomiPhone = [XiaoMiElectronFactory createPhone];
NSLog(@"computer name = %@", [xiaomiPhone productName]);
}
2.3.3 分析
- 抽象工厂模式除了具有工厂方法模式的优点外,可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理
- 当增加一个新的产品族时不需要修改原代码,满足开闭原则
- 但是当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改又与开闭原则相悖
2.3.4 适用范围
- 当要被创建的对象是一系列具有相互关联、相互依赖的产品类时
- 系统中有多个产品族,但是每次只会适用其中一个产品族的产品
- 涉及不同运行环境的时候,都可以考虑使用抽象工厂模式。例如一个应用,需要在三个不同平台(Windows、Linux、Android 通过抽象工厂模式屏蔽掉操作系统对应用的影响。三个不同操作系统上的软件功能、应用逻辑、UI都应该是非常类似的,唯一不同的是调用不同的工厂方法,由不同的产品类去处理与操作系统交互的信息