iOS設計模式之工廠方法
定義
工廠模式:定義建立物件的介面,讓子類決定例項化哪一個類,工廠方法使得一個類的例項化延遲到其子類。
使用場景
下列情況會適合使用工廠模式:
- 編譯時無法準確與其要建立的物件類
- 類想讓其子類決定在執行時建立什麼
- 類有若干個輔助類為其子類,而你想將返回某個子類這一資訊區域性化
在Cocoa Touch框架中,NSNumber就是典型的工廠方法構造。NSNumber通過類方法numberWithBool:介面例項化NSCFBoolean例項,將bool值引數傳遞給例項化物件。
類圖結構
工廠方法模式的類結構圖如下:
抽象的Product定義了建立物件的介面init。ConcreteProduct實現Product介面,返回自身的例項。Creator定義了返回Product物件的工廠方法。Creator可以有個一預設實現,返回預設的ConcreteProduct物件。ConcreteCreator是Creator的子類,過載工廠方法,返回ConcreteProduct的物件例項。建立時,根據ConcreteCreator例項來建立對應的ConcreteProduct例項,隱藏了ConcreteProduct的複雜建立過程。程式碼實現
下面我們來用程式碼實現下工廠模式。
需求如下:實現一個畫布頁面背景,根據使用者操作或者預設行為生成不同的背景圖,背景圖型別樣式會隨著需求不斷的新增。
實現如下:
@interface XQCanvasView : UIView
- (instancetype)initWithFrame:(CGRect)frame;
@end
複製程式碼
XQCanvasView是背景圖的父類,定義一個建立介面initWithFrame
@interface XQPaperCanvasView : XQCanvasView
@end
@implementation XQPaperCanvasView
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
UIImageView *imageView = [UIImageView new];
imageView.image = [UIImage imageNamed:@"paper.jpg"];
imageView.frame = frame;
[self addSubview:imageView];
}
return self;
}
@end
複製程式碼
XQPaperCanvasView實現父類的建立介面initWithFrame,增加紙紋理的背景
@interface XQClothCanvasView : XQCanvasView
@end
@implementation XQClothCanvasView
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
UIImageView *imageView = [UIImageView new];
imageView.image = [UIImage imageNamed:@"cloth.jpg"];
imageView.frame = frame;
[self addSubview:imageView];
}
return self;
}
@end
複製程式碼
XQClothCanvasView實現父類建立介面,增加布紋理的背景
@interface XQCanvasViewGenerator : NSObject
- (XQCanvasView *)canvasViewWithFrame:(CGRect)frame;
@end
@implementation XQCanvasViewGenerator
- (XQCanvasView *)canvasViewWithFrame:(CGRect)frame{
return [[XQCanvasView alloc] initWithFrame:frame];
}
@end
複製程式碼
XQCanvasViewGenerator為生產者的父類,定義一個建立畫布背景圖XQCanvasView的介面。預設實現返回一個空白的XQCanvasView
@interface XQPaperCanvasViewGenerator : XQCanvasViewGenerator
@end
@implementation XQPaperCanvasViewGenerator
- (XQCanvasView *)canvasViewWithFrame:(CGRect)frame{
return [[XQPaperCanvasView alloc] initWithFrame:frame];
}
@end
複製程式碼
XQPaperCanvasViewGenerator實現父類的canvasViewWithFrame工廠方法,生成XQPaperCanvasView的紙紋理背景物件。
@interface XQClothCanvasViewGenerator : XQCanvasViewGenerator
@end
@implementation XQClothCanvasViewGenerator
- (XQCanvasView *)canvasViewWithFrame:(CGRect)frame{
return [[XQClothCanvasView alloc] initWithFrame:frame];
}
@end
複製程式碼
XQClothCanvasViewGenerator實現父類的canvasViewWithFrame工廠方法,生成XQClothCanvasView的布紋理背景物件。
上面就是所有工廠方法涉及的類,下面看使用:
@interface XQCanvasViewController : UIViewController
- (void)loadCanvasViewWithGenerator:(XQCanvasViewGenerator *)generator;
@end
@interface XQCanvasViewController ()
@property (nonatomic,strong)XQCanvasView *canvasView;
@end
@implementation XQCanvasViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self loadCanvasViewWithGenerator:[XQClothCanvasViewGenerator new]];
}
- (void)loadCanvasViewWithGenerator:(XQCanvasViewGenerator *)generator{
[self.canvasView removeFromSuperview];
XQCanvasView *aCanvas = [generator canvasViewWithFrame:self.view.bounds];
self.canvasView = aCanvas;
[self.view addSubview:aCanvas];
}
@end
複製程式碼
畫布檢視控制器XQCanvasViewController定義了一個載入背景圖的方法loadCanvasViewWithGenerator,供外部呼叫配置不同的背景圖。在viewDidLoad中,呼叫[self loadCanvasViewWithGenerator:[XQClothCanvasViewGenerator new]];生成預設的布紋理背景圖。loadCanvasViewWithGenerator方法實現中,先移除上一次的背景圖self.canvasView,然後再用生成器generator生成對應的不同背景圖。
當需求新增其他型別複雜的背景圖時,只需新增對應的XQCanvasView背景圖子類,與其對應的XQCanvasViewGenerator生成器子類,在呼叫的地方傳遞新生成的XQCanvasViewGenerator生成器子類即可。
總結
工廠方法是在面向物件軟體設計中應用非常普遍的設計模式。工廠方法從程式碼中消除了對應用特有類的耦合,只需處理產品Product的抽象介面即可。