什么是工廠方法模式?
要了解工廠方法模式先要了解其中的四種角色:
工廠抽象類G:抽象類,主要是定義生產(chǎn)產(chǎn)品類的接口。
工廠子類g:繼承工廠抽象類梅鹦,實現(xiàn)工廠抽象類的接口,實例化相對應的產(chǎn)品子類冗锁。
產(chǎn)品抽象類C:定義產(chǎn)品的基本屬性和方法齐唆。
產(chǎn)品子類:具體的產(chǎn)品類,工廠子類實例化的對象冻河。
官方解釋工廠方法模式:定義一個用于創(chuàng)建對象的接口(工廠抽象類)箍邮,讓子類(工廠子類)決定實例化哪些類(產(chǎn)品子類),使一個類(產(chǎn)品子類)的實例化延遲到子類(工廠子類)叨叙。
我的解釋:創(chuàng)建G(工廠抽象類),g(工廠子類),C(產(chǎn)品抽象類),c(產(chǎn)品子類)四個類锭弊,G定義一個生產(chǎn)產(chǎn)品的接口如createProduct,g繼承G,g實現(xiàn)createProduct,創(chuàng)建c并將c返回擂错,c繼承C味滞。這樣項目如果要修改c時只需要修改g中createProduct方法中實例化的對象。
工廠方法模式的優(yōu)缺點:
優(yōu)點:
1.將實例化產(chǎn)品類全部歸到一個接口钮呀,當要換產(chǎn)品類時剑鞍,只需要修改接口中實例化的類就行了,而項目中的其他地方不用變換爽醋。
2.刪除和增加是變得容易,符合開放封閉原則
缺點:
1.如要要增加產(chǎn)品類時解愤,也要對應的增加工廠類。
工廠方法模式的代碼實現(xiàn):
1.創(chuàng)建一個形狀基類PFAbstractShape乎莉。該類中定義了形狀的基本行為和屬性奸笤,如下代碼所示:
PFAbstractShape.h
#import <Foundation/Foundation.h>
#define PF_Exception_Format @"在%@的子類中必須override:%@方法"
@interfacePFAbstractShape :NSObject
@property(nonatomic,weak)NSString*name;
//子類必須重寫這個draw方法,否則會拋出異常錯誤
-(void)draw;
@end
PFAbstractShape.m
#import"PFAbstractShape.h"
@implementationPFAbstractShape
-(void)draw
{
//如果是通過PFAbstractShape的實例調用此處的draw哼鬓,則繪制一個PFAbstractShape圖形
if([selfisMemberOfClass:[PFAbstractShapeclass]]) {
NSLog(@"繪制一個PFAbstractShape圖形");
}else{
//如果是通過PFAbstractShape子類的實例調用了此處的draw监右,則拋出一個異常:表明子類并沒有重寫draw方法授药。
//注:在OC中并沒有abstract class的概念岔激,只有protocol,如果在基類中只定義接口(沒有具體方法的實現(xiàn))江兢,
//則可以使用protocol昨忆,這樣會更方便。
[NSExceptionraise:NSInternalInconsistencyException
format:PF_Exception_Format, [NSStringstringWithUTF8String:object_getClassName(self)],NSStringFromSelector(_cmd)];
}
}
在上面的代碼中定義了一個draw方法杉允,為了讓子類必須實現(xiàn)該方法邑贴,在PFAbstractShape中做了特殊處理席里,具體內容可以看上面的代碼,已經(jīng)有注視了拢驾。
2.子類化形狀基類奖磁。首先子類化一個圓形類:PFCircleShape。
PFCircleShape.h
#import"PFAbstractShape.h"
@interfacePFCircleShape :PFAbstractShape
@end
PFCircleShape.m
#import"PFCircleShape.h"
@implementationPFCircleShape
- (void)draw
{
NSLog(@"繪制一個PFCircleShape圖形");
}
@end
在上面的子類中繁疤,重寫了基類的draw方法咖为。同樣,我們再子類化一個正方形類稠腊,并重寫draw方法躁染,如下代碼所示:
PFSquareShape.h
#import"PFAbstractShape.h"
@interfacePFSquareShape :PFAbstractShape
@end
PFSquareShape.m
#import"PFSquareShape.h"
@implementationPFSquareShape
- (void)draw
{
NSLog(@"繪制一個PFSquareShape圖形");
}
@end
3.創(chuàng)建一個工廠方法的基類PFAbstractFactory
PFAbstractFactory.h
#import<Foundation/Foundation.h>
#import"PFAbstractShape.h"
@interfacePFAbstractFactory :NSObject
- (PFAbstractShape*)factoryMethod;
@end
PFAbstractFactory.m
#import"PFAbstractFactory.h"
@implementationPFAbstractFactory
-(PFAbstractShape*)factoryMethod
{
//在此處,子類必須重寫factoryMethod方法麻养。當然褐啡,在工廠模式中,也可以在此處返回一個默認的Product鳖昌。
//如果是通過PFAbstractFactory子類的實例調用了此處的factoryMethod备畦,則拋出一個異常:表明子類并沒有重寫factoryMethod方法。
[NSExceptionraise:NSInternalInconsistencyException
format:PF_Exception_Format, [NSStringstringWithUTF8String:object_getClassName(self)],NSStringFromSelector(_cmd)];
//下面這個return語句只是為了消除警告许昨,實際上永遠都不會執(zhí)行到這里懂盐。
returnnil;
}
@end
在上面的代碼中,定義了一個factoryMethod糕档,該類的子類必須實現(xiàn)該方法莉恼,通過實現(xiàn)該方法,返回一個具體的形狀對象速那。下面來看看該類的子類化俐银。
4.子類化工廠方法的基類。首先子類化一個圓形工廠方法PFCircleShapeFactory:
PFCircleShapeFactory.h
#import"PFAbstractFactory.h"
#import"PFCircleShape.h"
@interfacePFCircleShapeFactory :PFAbstractFactory
@end
PFCircleShapeFactory.m
#import"PFCircleShapeFactory.h"
@implementationPFCircleShapeFactory
- (PFAbstractShape*)factoryMethod
{
return[[PFCircleShapealloc]init];
}
@end
如上代碼所示端仰,重寫了factoryMethod捶惜,返回一個PFCircleShape實例。下面來看看另外一個子類PFSquareShapeFactory:
PFSquareShapeFactory.h
#import"PFAbstractFactory.h"
#import"PFSquareShape.h"
@interfacePFSquareShapeFactory :PFAbstractFactory
@end
PFSquareShapeFactory.m
#import"PFSquareShapeFactory.h"
@implementationPFSquareShapeFactory
- (PFAbstractShape*)factoryMethod{
return[[PFSquareShapealloc]init];
}
@end
該子類返回的是一個PFSquareShape實例荔烧。
5.工廠方法的使用吱七。定義一個PFClient類,在該類中演示工廠方法的使用鹤竭。代碼如下:
PFClient.h
#import
@interfacePFClient :NSObject
- (void)doSomething;
@end
PFClient.m
#import"PFClient.h"
#import"PFAbstractFactory.h"
#import"PFCircleShapeFactory.h"
#import"PFSquareShapeFactory.h"
#import"PFAbstractShape.h"
#import"PFCircleShape.h"
#import"PFSquareShape.h"
@implementationPFClient
-(void)doSomething
{
//用到多態(tài)踊餐,父指針指向子對象,當要修改實例化的對象時臀稚,只需要修改工廠里的實例化對象
//工廠方法的實例化
PFAbstractFactory*circleShapefactory = [[PFCircleShapeFactoryalloc]init];
PFAbstractFactory*squareShapefactory = [[PFSquareShapeFactoryalloc]init];
//通過工廠方法實例化對應的形狀
PFAbstractShape*circleShape = [circleShapefactoryfactoryMethod];
PFAbstractShape*squareShape = [squareShapefactoryfactoryMethod];
//調用形狀的方法
[circleShapedraw];
[squareShapedraw];
}
@end
如上代碼所示吝岭,首先實例化兩個工廠方法,并通過工廠方法創(chuàng)建出對應的形狀,最后調用形狀的draw方法進行測試苍碟。會在控制臺窗口輸出如下內容:
2013-05-16 10:12:46.292 FactoryMethodPattern[2845:c07] 繪制一個PFCircleShape圖形
2013-05-16 10:12:46.295 FactoryMethodPattern[2845:c07] 繪制一個PFSquareShape圖形