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.”
- 簡(jiǎn)單工廠模式(Simple Factory)
- 工廠方法模式(Factory Method)
- 抽象工廠模式(Abstract Factory)
簡(jiǎn)單工廠模式
簡(jiǎn)單工廠使用場(chǎng)景
- 簡(jiǎn)化生產(chǎn)流程
- 隔離生產(chǎn)產(chǎn)品的細(xì)節(jié)
- 不同類型的產(chǎn)品之間有著一些共同的功能
- 一個(gè)具體的工廠
抽象工廠模式
工廠方法把生產(chǎn)產(chǎn)品的方式封裝起來了,但是一個(gè)工廠只能生產(chǎn)一類對(duì)象,當(dāng)一個(gè)工廠需要生產(chǎn)多類產(chǎn)品的時(shí)候,就需要使用抽象工廠了。抽象工廠(AbstractFactory)類定義了一組標(biāo)準(zhǔn)的實(shí)現(xiàn)接口,這些接口一般都是和具體的產(chǎn)品類繼承層次對(duì)應(yīng)的。如createProductA接口只能生產(chǎn)抽象產(chǎn)品類(AbstratctProductA)的子類產(chǎn)品,因此抽象工廠的具體實(shí)現(xiàn)類之間的關(guān)系就是個(gè)生產(chǎn)了一批不同產(chǎn)品族的組合。這樣通過抽象工廠模式可以方便的更換產(chǎn)品族,代碼修改的代價(jià)只需要更換一個(gè)具體的工廠對(duì)象就可以了。因此直觀上可以把抽象工廠看作一組工廠方法,它的每一個(gè)接口都可以提取出一個(gè)單獨(dú)的工廠方法。不過抽象工廠除了反映出這些含義外,還隱含著多類產(chǎn)品之間有種內(nèi)在的聯(lián)系,如按鈕、菜單、滾動(dòng)條都是GUI組件。
舉例:
對(duì)于可以隨意更換GUI組件庫(kù)的需求,抽象工廠就可以完成類似的功能。抽象工廠類(AbstractFactory)封裝了GUI組件庫(kù)必須提供的接口,如創(chuàng)建按鈕、菜單、滾動(dòng)條等。GUI組件類會(huì)根據(jù)不同的窗口系統(tǒng)而派生具體的組件類,實(shí)現(xiàn)抽象工廠的具體類具體工廠類會(huì)根據(jù)不同的窗口系統(tǒng)選擇對(duì)應(yīng)的組件進(jìn)行生產(chǎn)。這樣當(dāng)更換窗口系統(tǒng)的時(shí)候,只需要更換工廠類就能方便的實(shí)現(xiàn)運(yùn)行時(shí)窗口系統(tǒng)的更換。按照這樣的描述,我們用C++實(shí)現(xiàn)的代碼如下:
//產(chǎn)品類繼承層次
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();
}
};
如果我們使用這段代碼創(chuàng)建組件,就會(huì)這么寫了:
GUIFactory*factory=new WindowsGUIFactory();//創(chuàng)建工廠
Button*btn=factory->createButton();//創(chuàng)建按鈕
Menu*menu=factory->createMenu();//創(chuàng)建菜單
btn->click();//調(diào)用組件函數(shù)
menu->select();
delete menu;
delete btn;
delete factory;
從代碼中看出我們無法看到看到具體創(chuàng)建的組件,因?yàn)槲覀冎恍枰贸橄箢怋utton、Menu使用標(biāo)準(zhǔn)的接口就可以了,具體的實(shí)現(xiàn)被工廠封裝起來了。如果我們要更換所有的一批組件的話,只需要修改第一行代碼,換一個(gè)工廠就可以了。
下面用Objective-C語(yǔ)言寫個(gè)抽象工廠的例子。
工廠父類:抽象工廠
#import <Foundation/Foundation.h>
#import "BasePhone.h"
#import "BaseWatch.h"
@interface BaseFactory : NSObject
/**
* 創(chuàng)建手機(jī)
*
* @return 手機(jī)
*/
- (BasePhone *)createPhone;
/**
* 創(chuàng)建手表
*
* @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
具體的設(shè)備也是先創(chuàng)建設(shè)備的父類BasePhone和BaseWatch,再創(chuàng)建繼承自它們倆的子類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 創(chuàng)建出的工廠
*/
+ (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
具體工廠的創(chuàng)建方法如下:
// 獲取工廠
BaseFactory *factory = [FactoryManager factoryWithBrand:kGoogle];
// 創(chuàng)建商品
BasePhone *phone = [factory createPhone];
BaseWatch *watch = [factory createWatch];
簡(jiǎn)單工廠模式
手機(jī)協(xié)議
#import <Foundation/Foundation.h>
@protocol PhoneProtocol <NSObject>
@required
/**
* 打電話
*/
- (void)phoneCall;
/**
* 發(fā)短信
*/
- (void)sendMessage;
@end
設(shè)備父類
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
具體設(shè)備
iPhone設(shè)備
#import "BaseDevie.h"
@interface iPhoneDevice : BaseDevie
/**
* 指紋識(shí)別
*/
- (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設(shè)備
#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
手機(jī)設(shè)備工廠
#import <Foundation/Foundation.h>
#import "BaseDevie.h"
#import "iPhoneDevice.h"
#import "AndroidDevice.h"
typedef NS_ENUM(NSUInteger, EDevieType) {
kiPhone = 0x11,
kAndroid,
} ;
@interface DeviceFactory : NSObject
/**
* 根據(jù)用戶提交的指令創(chuàng)建出具體的手機(jī)
*
* @param type 創(chuàng)建的指令
*
* @return 創(chuàng)建出的手機(jī)
*/
+ (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
簡(jiǎn)單工廠實(shí)現(xiàn)
// 工廠中創(chuàng)建出具體產(chǎn)品
iPhoneDevice *iPhone = (iPhoneDevice *)[DeviceFactory deviceFactoryWithDevieType:kiPhone];
// 使用產(chǎn)品的功能
[iPhone fingerprintIndetification];
工廠模式是最重要的模式,因?yàn)榇蠖鄶?shù)模式都需要用到工廠模式。如果不能正確的運(yùn)用工廠模式,那么可以說無法成為合格的架構(gòu)師。
工廠方法模式:
一個(gè)抽象產(chǎn)品類,可以派生出多個(gè)具體產(chǎn)品類。
一個(gè)抽象工廠類,可以派生出多個(gè)具體工廠類。
每個(gè)具體工廠類只能創(chuàng)建一個(gè)具體產(chǎn)品類的實(shí)例。
抽象工廠模式:
多個(gè)抽象產(chǎn)品類,每個(gè)抽象產(chǎn)品類可以派生出多個(gè)具體產(chǎn)品類。
一個(gè)抽象工廠類,可以派生出多個(gè)具體工廠類。
每個(gè)具體工廠類可以創(chuàng)建多個(gè)具體產(chǎn)品類的實(shí)例。
區(qū)別:
工廠方法模式只有一個(gè)抽象產(chǎn)品類,而抽象工廠模式有多個(gè)。
工廠方法模式的具體工廠類只能創(chuàng)建一個(gè)具體產(chǎn)品類的實(shí)例,而抽象工廠模式可以創(chuàng)建多個(gè)。
在iOS的系統(tǒng)類庫(kù)中也有一種方式使得開發(fā)者不必關(guān)注類中具體的存儲(chǔ)實(shí)現(xiàn),但可以根據(jù)不同需求場(chǎng)景創(chuàng)建出合適的對(duì)象來。
在iOS中有很多類都是使用了工廠模式,例如
Foundation:
NSNumber,
NSArray,
UIKit:
UIButton等類。