意圖:
提供一個接口,用來創(chuàng)建一組相關(guān)或者相互依賴的對象,而無需指定他們的具體類
適用范圍:
提供一個產(chǎn)品類庫,顯示它們的接口,隱藏具體實現(xiàn),使系統(tǒng)獨立于產(chǎn)品的創(chuàng)建、組合、表示
缺點:
當有新增品類的時候,同時需要拓展抽象工廠和具體工廠
解決方案:
抽象工廠需要更抽象,不再關(guān)心產(chǎn)品的品類,具體工廠需要更具體,只提供一種產(chǎn)品的規(guī)格參數(shù)
具體實現(xiàn):
通過反射機制運行時動態(tài)創(chuàng)建產(chǎn)品,具體工廠不再負責生產(chǎn),而是提供產(chǎn)品的具體參數(shù),抽象工廠通過產(chǎn)品參數(shù)反射出具體工廠,然后生產(chǎn)一個產(chǎn)品
實踐-app殼工程
大型app基本都經(jīng)歷過從簡單架構(gòu)到復(fù)雜架構(gòu)的演進,像支付寶、美團這種體量的app不拆分業(yè)務(wù)線簡直就是災(zāi)難,本文以一個app為工廠,該工廠生產(chǎn)各種業(yè)務(wù)線,就拿美團來舉例,有騎行、打車、電影、外賣業(yè)務(wù)線
定義一個業(yè)務(wù)線工廠協(xié)議AbstractFactoryProtocol.h,該協(xié)議只描述各個業(yè)務(wù)線的通用行為,比如是否是單例
@protocol AbstractFactoryProtocol <NSObject>
@optional
+ (id)shareInstance;
@end
定義一個抽象工廠類AbstractFactory,用單例來描述,該類負責通過產(chǎn)品規(guī)格參數(shù),反射出具體工廠,然后生產(chǎn)產(chǎn)品
@interface AbstractFactory : NSObject
+ (instancetype)sharedFactory;
- (id)createProduct:(Protocol *)protocol;
@end
AbstractFactory的實現(xiàn)內(nèi)容如下
static NSString *kProtocol = @"FactoryMethodProtocol";
static NSString *kViewController = @"Page";
@implementation AbstractFactory
+ (instancetype)sharedFactory {
static id sharedFactory = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedFactory = [[self alloc] init];
});
return sharedFactory;
}
- (id)createProduct:(Protocol *)protocol {
NSString *protocolName = NSStringFromProtocol(protocol);
NSString *className = [protocolName stringByReplacingOccurrencesOfString:kProtocol withString:kViewController];
Class implClass = NSClassFromString(className);
if (!implClass) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"%@ protocol does not have match class", protocolName] userInfo:nil];
}
if ([[implClass class] respondsToSelector:@selector(shareInstance)]) {
return [[implClass class] shareInstance];
}
return [[implClass alloc] init];
}
@end
定義一個具體工廠集合SpecificProducts.h
#ifndef SpecificProducts_h
#define SpecificProducts_h
#import "BikeFactoryMethodProtocol.h"
#import "CarFactoryMethodProtocol.h"
#import "MovieFactoryMethodProtocol.h"
#import "TakeoutFactoryMethodProtocol.h"
#endif /* SpecificProducts_h */
具體工廠繼承抽象工廠協(xié)議
@protocol BikeFactoryMethodProtocol <NSObject, AbstractFactoryProtocol>
@end
定義具體產(chǎn)品,騎行、打車、電影、外賣
@interface BikePage : UIViewController
@end
@interface CarPage : UIViewController
@end
@interface MoviePage : UIViewController
@end
@interface TakeoutPage : UIViewController
@end
客戶端只需要引用抽象工廠和具體工廠集合即可生產(chǎn)所有產(chǎn)品
id<BikeFactoryMethodProtocol> item0 = [[AbstractFactory sharedFactory] createProduct:@protocol(BikeFactoryMethodProtocol)];
id<CarFactoryMethodProtocol> item1 = [[AbstractFactory sharedFactory] createProduct:@protocol(CarFactoryMethodProtocol)];
id<MovieFactoryMethodProtocol> item2 = [[AbstractFactory sharedFactory] createProduct:@protocol(MovieFactoryMethodProtocol)];
id<TakeoutFactoryMethodProtocol> item3 = [[AbstractFactory sharedFactory] createProduct:@protocol(TakeoutFactoryMethodProtocol)];
總結(jié)
更具體的做法是,各個業(yè)務(wù)線會拆包開發(fā),各自維護自己的業(yè)務(wù)線協(xié)議,新增業(yè)務(wù)線只需要在殼工程配置自己的協(xié)議即可,本文demo地址,該方案彌補了抽象工廠模式的拓展問題,但是存在字符串硬編碼問題,若有類和協(xié)議不匹配會拋出異常,這里推薦阿里出品的iOS解耦神器BeeHive,它的做法是,用一個全局的字典保存協(xié)議與類名字的映射關(guān)系,當然這也是一種硬編碼,只不過用起來更靈活,協(xié)議和類可以隨意命名