前言
????幾乎在每個面向?qū)ο笳Z言寫的應用程序里都能看到工廠方法。對象工廠與生成有形產(chǎn)品的真實工廠類似,例如:制鞋廠生產(chǎn)鞋,手機工廠生產(chǎn)手機。比方說,你讓工廠給你生產(chǎn)些產(chǎn)品,發(fā)送一個 “生產(chǎn)產(chǎn)品” 的消息,工廠按照相同的 “生產(chǎn)產(chǎn)品的協(xié)議” ,啟動其生產(chǎn)線,過程結(jié)束后,每個廠家都返回所生產(chǎn)的特定類型的產(chǎn)品。我們把 ”生產(chǎn)“ 這個有魔力的詞稱作工廠方法,因為它是命令生產(chǎn)者得到想要的產(chǎn)品的方法。
什么是工廠方法模式
????工廠方法,也成為虛構(gòu)造器。定義一個創(chuàng)建對象的接口,讓其子類自己決定實例化哪一個工廠類,工廠方法模式使其創(chuàng)建過程延遲到子類進行。其從代碼中消除了對特有類的耦合,只需處理抽象接口,同一代碼得到復用。

????抽象的 Product 定義了工廠方法創(chuàng)建的對象的接口,ConcreteProduct 實現(xiàn)了 Product 的接口。Factory 定義了返回 Product 對象的工廠方法,ConcreteFactory 重載了工廠方法,返回 ConcreteProduct 實例。
什么時候使用工廠方法
- 編譯時無法準確預期要創(chuàng)建的對象的類
- 類想讓其子類決定在運行時創(chuàng)建什么
- 類有若干輔助類為其子類,將返回哪個子類這一信息局部化。
工廠方法使用場景舉例
- 日志記錄器:記錄可能記錄到本地硬盤、系統(tǒng)事件、遠程服務器等,用戶可以選擇記錄日志到什么地方。
- 數(shù)據(jù)庫訪問:當不知道最后系統(tǒng)采用哪一類數(shù)據(jù)庫,以及數(shù)據(jù)庫可能有變化時。
工廠方法的優(yōu)缺點
優(yōu)點:
- 一個調(diào)用者想創(chuàng)建一個對象,只要知道其名稱就可以了。
- 擴展性高,如果想增加一個產(chǎn)品,只要擴展一個工廠類就可以,無需調(diào)用的代碼
- 屏蔽產(chǎn)品的具體實現(xiàn),調(diào)用者只關(guān)心產(chǎn)品的接口。
缺點
- 每次增加一個產(chǎn)品時,都需要增加一個具體類和對象實現(xiàn)工廠,使得系統(tǒng)中類的個數(shù)成倍增加,在一定程度上增加了系統(tǒng)的復雜度,同時也增加了系統(tǒng)具體類的依賴。
實現(xiàn)
普通工廠方法的實現(xiàn)
-
定義一個抽象
Shape協(xié)議。@protocol Shape <NSObject> @property (nonatomic, copy) NSString *Id; @property (nonatomic, copy) NSString *type; - (void)draw; @end -
定義三個 Shape 的子類分別為
Rectangle、Circle和Square@interface Rectangle : NSObject<Shape> @end @implementation Rectangle @synthesize Id; @synthesize type; - (instancetype)init { self = [super init]; if (self) { self.type = @"Rectangle"; } return self; } - (void)draw{ NSLog(@"call Rectangle draw() method."); } @end @interface Circle : NSObject<Shape> @end @implementation Circle @synthesize Id; @synthesize type; - (instancetype)init { self = [super init]; if (self) { self.type = @"Circle"; } return self; } - (void)draw{ NSLog(@"call Circle draw() method."); } @end @interface Square : NSObject<Shape> @end @implementation Square @synthesize Id; @synthesize type; - (instancetype)init { self = [super init]; if (self) { self.type = @"Square"; } return self; } - (void)draw{ NSLog(@"call Square draw() method."); } @end
-
定義一個
ShapeFactory抽象@protocol,負責創(chuàng)建Shape,以及遵守協(xié)調(diào)的CircleFactory、RectangleFactory和SquareFactory負責創(chuàng)建Circle、Rectangle和Square。@protocol ShapeFactory - (id<Shape>)shapeWithId:(NSString *)Id; @end @interface CircleFactory : NSObject <ShapeFactory> @end @implementation CircleFactory - (Circle *)shapeWithId:(NSString *)Id{ Circle *circle = [Circle new]; circle.Id = Id; return circle; } @end @interface RectangleFactory : NSObject <ShapeFactory> @end @implementation RectangleFactory - (id<Shape>)shapeWithId:(NSString *)Id{ Rectangle *rectangle = [Rectangle new]; rectangle.Id = Id; return rectangle; } @end @interface SquareFactory : NSObject <ShapeFactory> @end @implementation SquareFactory - (id<Shape>)shapeWithId:(NSString *)Id{ Square *square = [Square new]; square.Id = Id; return square; } -
執(zhí)行方法為:
- (id<Shape>)loadShapeWithFactory:(id<ShapeFactory>)factory- (id<Shape>)loadShapeWithId:(NSString *)Id Factory:(ShapeFactory *)factory{ return [factory shapeWithId:Id]; }
-
通過傳入不同的
Factory,獲得不同類型的Shape。例如:[self loadShapeWithId:@"2" Factory:[CircleFactory new]];
簡單工廠方法
????在簡單工廠中,可以根據(jù)參數(shù)的不同返回不同類的實例。簡單工廠專門定義一個 Factory 類來負責創(chuàng)建其他類的實例,被創(chuàng)建的實例通常都具有共同的父類。例如,刪除上面的各個工廠,統(tǒng)一由 ShapeFactroy類根據(jù)遵守Shape 類型的類名反射創(chuàng)建子類的實例。
@interface ShapeFactory : NSObject
+ (id<Shape>)shapeWithId:(NSString *)Id Type:(NSString *)type;
@end
@implementation ShapeFactory
+ (id<Shape>)shapeWithId:(NSString *)Id Type:(NSString *)type{
Class class = NSClassFromString(type);
if ([class conformsToProtocol:@protocol(Shape)]) {
id <Shape>object = [class new];
object.Id = Id;
return object;
}
return nil;
}
@end
可以將簡單工廠看為工廠方法模式的一個特例,將全部創(chuàng)建邏輯集中到了一個工廠類中;它所能創(chuàng)建的類只能是事先考慮到的,如果需要添加新的類,則就需要改變工廠類了。
總結(jié)
????工廠方法是面向?qū)ο筌浖O(shè)計中應用非常普遍的設(shè)計模式。工廠方法從代碼中消除了對應用程序特有類的耦合。代碼只需要處理 <Product> 抽象接口,所以同一代碼得到復用,在應用程序中與用戶定義的任何 ConcreteProduct 實體類一起工作。