GOF是这样描述工厂模式的:
“Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.”
- 简单工厂模式(Simple Factory)
- 工厂方法模式(Factory Method)
- 抽象工厂模式(Abstract Factory)
简单工厂模式
简单工厂使用场景
- 简化生产流程
- 隔离生产产品的细节
- 不同类型的产品之间有着一些共同的功能
- 一个具体的工厂
抽象工厂模式
工厂方法把生产产品的方式封装起来了,但是一个工厂只能生产一类对象,当一个工厂需要生产多类产品的时候,就需要使用抽象工厂了。抽象工厂(AbstractFactory)类定义了一组标准的实现接口,这些接口一般都是和具体的产品类继承层次对应的。如createProductA接口只能生产抽象产品类(AbstratctProductA)的子类产品,因此抽象工厂的具体实现类之间的关系就是个生产了一批不同产品族的组合。这样通过抽象工厂模式可以方便的更换产品族,代码修改的代价只需要更换一个具体的工厂对象就可以了。因此直观上可以把抽象工厂看作一组工厂方法,它的每一个接口都可以提取出一个单独的工厂方法。不过抽象工厂除了反映出这些含义外,还隐含着多类产品之间有种内在的联系,如按钮、菜单、滚动条都是GUI组件。
举例:
对于可以随意更换GUI组件库的需求,抽象工厂就可以完成类似的功能。抽象工厂类(AbstractFactory)封装了GUI组件库必须提供的接口,如创建按钮、菜单、滚动条等。GUI组件类会根据不同的窗口系统而派生具体的组件类,实现抽象工厂的具体类具体工厂类会根据不同的窗口系统选择对应的组件进行生产。这样当更换窗口系统的时候,只需要更换工厂类就能方便的实现运行时窗口系统的更换。按照这样的描述,我们用C++实现的代码如下:
//产品类继承层次
class Button
{
public:
virtual void click()=0;
virtual ~Button(){}
};
class WindowsButton:public Button
{
public:
virtual void click()
{
cout<<"单击了Windows按钮"<<endl;
}
};
class MacButton:public Button
{
public:
virtual void click()
{
cout<<"单击了Mac按钮"<<endl;
}
};
class Menu
{
public:
virtual void select()=0;
virtual ~Menu(){}
};
class WindowsMenu:public Menu
{
public:
virtual void select()
{
cout<<"选择了Windows菜单"<<endl;
}
};
class MacMenu:public Menu
{
public:
virtual void select()
{
cout<<"选择了Mac菜单"<<endl;
}
};
//抽象工厂
class GUIFactory
{
public:
virtual Button*createButton()=0;
virtual Menu*createMenu()=0;
virtual ~GUIFactory(){}
};
//具体的工厂
class WindowsGUIFactory:public GUIFactory
{
public:
virtual Button*createButton()
{
return new WindowsButton();
}
virtual Menu*createMenu()
{
return new WindowsMenu();
}
};
class MacGUIFactory:public GUIFactory
{
public:
virtual Button*createButton()
{
return new MacButton();
}
virtual Menu*createMenu()
{
return new MacMenu();
}
};
如果我们使用这段代码创建组件,就会这么写了:
GUIFactory*factory=new WindowsGUIFactory();//创建工厂
Button*btn=factory->createButton();//创建按钮
Menu*menu=factory->createMenu();//创建菜单
btn->click();//调用组件函数
menu->select();
delete menu;
delete btn;
delete factory;
从代码中看出我们无法看到看到具体创建的组件,因为我们只需要用抽象类Button、Menu使用标准的接口就可以了,具体的实现被工厂封装起来了。如果我们要更换所有的一批组件的话,只需要修改第一行代码,换一个工厂就可以了。
下面用Objective-C语言写个抽象工厂的例子。
工厂父类:抽象工厂
#import <Foundation/Foundation.h>
#import "BasePhone.h"
#import "BaseWatch.h"
@interface BaseFactory : NSObject
/**
* 创建手机
*
* @return 手机
*/
- (BasePhone *)createPhone;
/**
* 创建手表
*
* @return 手表
*/
- (BaseWatch *)createWatch;
@end
#import "BaseFactory.h"
@implementation BaseFactory
- (BasePhone *)createPhone {
return nil;
}
- (BaseWatch *)createWatch {
return nil;
}
@end
工厂子类:具体工厂
// 苹果工厂
#import "BaseFactory.h"
@interface AppleFactory : BaseFactory
@end
#import "AppleFactory.h"
#import "iPhone.h"
#import "AppleWatch.h"
@implementation AppleFactory
- (BasePhone *)createPhone {
return [[iPhone alloc] init];
}
- (BaseWatch *)createWatch {
return [[AppleWatch alloc] init];
}
// 谷歌工厂
#import "BaseFactory.h"
@interface GoogleFactory : BaseFactory
@end
#import "GoogleFactory.h"
#import "Android.h"
#import "AndroidWatch.h"
@implementation GoogleFactory
- (BasePhone *)createPhone {
return [[Android alloc] init];
}
- (BaseWatch *)createWatch {
return [[AndroidWatch alloc] init];
}
@end
具体的设备也是先创建设备的父类BasePhone和BaseWatch,再创建继承自它们俩的子类iPhone,Android,AppleWatch,AndroidWatch。
工厂管理类
#import <Foundation/Foundation.h>
#import "BaseFactory.h"
#import "AppleFactory.h"
#import "GoogleFactory.h"
typedef NS_ENUM(NSUInteger, EFactoryType) {
kApple = 0x11,
kGoogle,
};
@interface FactoryManager : NSObject
/**
* 获取工厂
*
* @param factoryType 工厂类型
*
* @return 创建出的工厂
*/
+ (BaseFactory *)factoryWithBrand:(EFactoryType)factoryType;
@end
#import "FactoryManager.h"
@implementation FactoryManager
+ (BaseFactory *)factoryWithBrand:(EFactoryType)factoryType {
BaseFactory *factory = nil;
if (factoryType == kApple) {
factory = [[AppleFactory alloc] init];
} else if (factoryType == kGoogle) {
factory = [[GoogleFactory alloc] init];
}
return factory;
}
@end
具体工厂的创建方法如下:
// 获取工厂
BaseFactory *factory = [FactoryManager factoryWithBrand:kGoogle];
// 创建商品
BasePhone *phone = [factory createPhone];
BaseWatch *watch = [factory createWatch];
简单工厂模式
手机协议
#import <Foundation/Foundation.h>
@protocol PhoneProtocol <NSObject>
@required
/**
* 打电话
*/
- (void)phoneCall;
/**
* 发短信
*/
- (void)sendMessage;
@end
设备父类
BaseDevice.h
#import <Foundation/Foundation.h>
#import "PhoneProtocol.h"
@interface BaseDevie : NSObject <PhoneProtocol>
@end
BaseDevice.m
#import "BaseDevie.h"
@implementation BaseDevie
- (void)phoneCall {
}
- (void)sendMessage {
}
@end
具体设备
iPhone设备
#import "BaseDevie.h"
@interface iPhoneDevice : BaseDevie
/**
* 指纹识别
*/
- (void)fingerprintIndetification;
@end
#import "iPhoneDevice.h"
@implementation iPhoneDevice
- (void)phoneCall {
NSLog(@"iPhone phoneCall");
}
- (void)sendMessage {
NSLog(@"iPhone sendMessage");
}
- (void)fingerprintIndetification {
NSLog(@"iPhone fingerprintIndetification");
}
@end
Android设备
#import "BaseDevie.h"
@interface AndroidDevice : BaseDevie
/**
* 定制主题
*/
- (void)customTheme;
@end
#import "AndroidDevice.h"
@implementation AndroidDevice
- (void)phoneCall {
NSLog(@"Android phoneCall");
}
- (void)sendMessage {
NSLog(@"Android sendMessage");
}
- (void)customTheme {
NSLog(@"Android customTheme");
}
@end
手机设备工厂
#import <Foundation/Foundation.h>
#import "BaseDevie.h"
#import "iPhoneDevice.h"
#import "AndroidDevice.h"
typedef NS_ENUM(NSUInteger, EDevieType) {
kiPhone = 0x11,
kAndroid,
} ;
@interface DeviceFactory : NSObject
/**
* 根据用户提交的指令创建出具体的手机
*
* @param type 创建的指令
*
* @return 创建出的手机
*/
+ (BaseDevie <PhoneProtocol> *)deviceFactoryWithDevieType:(EDevieType)type;
@end
#import "DeviceFactory.h"
@implementation DeviceFactory
+ (BaseDevie <PhoneProtocol> *)deviceFactoryWithDevieType:(EDevieType)type {
BaseDevie <PhoneProtocol> *device = nil;
if (type == kiPhone) {
device = [[iPhoneDevice alloc] init];
} else if (type == kAndroid) {
device = [[AndroidDevice alloc] init];
}
return device;
}
@end
简单工厂实现
// 工厂中创建出具体产品
iPhoneDevice *iPhone = (iPhoneDevice *)[DeviceFactory deviceFactoryWithDevieType:kiPhone];
// 使用产品的功能
[iPhone fingerprintIndetification];
工厂模式是最重要的模式,因为大多数模式都需要用到工厂模式。如果不能正确的运用工厂模式,那么可以说无法成为合格的架构师。
工厂方法模式:
一个抽象产品类,可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式:
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类可以创建多个具体产品类的实例。
区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
在iOS的系统类库中也有一种方式使得开发者不必关注类中具体的存储实现,但可以根据不同需求场景创建出合适的对象来。
在iOS中有很多类都是使用了工厂模式,例如
Foundation:
NSNumber,
NSArray,
UIKit:
UIButton等类。