《禪與 Objective-C 編程藝術(shù)學(xué)習(xí)》是一本開源的電子書纸型,你可以把它當(dāng)做一本編程規(guī)范的書來看,也可以看做是一本 Effective Objective-C梅忌,電子書傳送門:禪與 Objective-C 編程藝術(shù)學(xué)習(xí)狰腌,非常推薦大家看一看。
類簇介紹(Class Clusters)
類簇在Apple的文檔中這樣描述:
an architecture that groups a number of private, concrete subclasses under a public, abstract superclass. (一個(gè)在共有的抽象超類下設(shè)置一組私有子類的架構(gòu))
如果這個(gè)描述聽起來很熟悉牧氮,說明你的直覺是對(duì)的琼腔。 Class cluster 是 Apple 對(duì)抽象工廠設(shè)計(jì)模式的稱呼。
Class Clusters 的想法很簡單: 使用信息進(jìn)行(類的)初始化處理期間踱葛,會(huì)使用一個(gè)抽象類(通常作為初始化方法的參數(shù)或者判定環(huán)境的可用性參數(shù))來完成特定的邏輯或者實(shí)例化一個(gè)具體的子類丹莲。而這個(gè)"Public Facing(面向公眾的)"類,必須非常清楚他的私有子類尸诽,以便在面對(duì)具體任務(wù)的時(shí)候有能力返回一個(gè)恰當(dāng)?shù)乃接凶宇悓?shí)例甥材。對(duì)調(diào)用者來說只需知道對(duì)象的各種API的作用即可。這個(gè)模式隱藏了他背后復(fù)雜的初始化邏輯性含,調(diào)用者也不需要關(guān)心背后的實(shí)現(xiàn)洲赵。
Class Clusters 在 Apple 的Framework 中廣泛使用:一些明顯的例子比如 NSNumber
可以返回不同類型給你的子類,取決于 數(shù)字類型如何提供 (Integer, Float, etc...) 或者 NSArray
返回不同的最優(yōu)存儲(chǔ)策略的子類胶滋。
這個(gè)模式的精妙的地方在于板鬓,調(diào)用者可以完全不管子類,只需使用簡單地接口究恤,就可以得到實(shí)際的返回的類俭令,而不用去管相關(guān)的細(xì)節(jié)。
我們的經(jīng)驗(yàn)是使用類簇可以幫助移除很多條件語句部宿。
類簇實(shí)例
一個(gè)經(jīng)典的例子是如果你有為 iPad 和 iPhone 寫的一樣的 UIViewController
子類抄腔,但是在不同的設(shè)備上有不同的行為瓢湃。
比較基礎(chǔ)的實(shí)現(xiàn)是用條件語句檢查設(shè)備,然后執(zhí)行不同的邏輯赫蛇。雖然剛開始可能不錯(cuò)绵患,但是隨著代碼的增長,運(yùn)行邏輯也會(huì)趨于復(fù)雜悟耘。 一個(gè)更好的實(shí)現(xiàn)的設(shè)計(jì)是創(chuàng)建一個(gè)抽象而且寬泛的 view controller 來包含所有的共享邏輯落蝙,并且對(duì)于不同設(shè)備有兩個(gè)特別的子例。
通用的 view controller 會(huì)檢查當(dāng)前設(shè)備并且返回適當(dāng)?shù)淖宇悺?/p>
@implementation ZOCKintsugiPhotoViewController
- (id)initWithPhotos:(NSArray *)photos
{
// 1.
if ([self isMemberOfClass:ZOCKintsugiPhotoViewController.class]) {
//2.
self = nil;
//3.
if ([UIDevice isPad]) {
self = [[ZOCKintsugiPhotoViewController_iPad alloc] initWithPhotos:photos];
}
else {
self = [[ZOCKintsugiPhotoViewController_iPhone alloc] initWithPhotos:photos];
}
return self;
}
return [super initWithNibName:nil bundle:nil];
}
@end
@implementation ZOCKintsugiPhotoViewController_iPad
- (instancetype)initWithPhotos:(NSArray *)photos {
//...
}
@end
@implementation ZOCKintsugiPhotoViewController_iPhone
- (instancetype)initWithPhotos:(NSArray *)photos {
//...
}
@end
這個(gè)實(shí)例展示了如何創(chuàng)建一個(gè)類簇暂幼。
isMemberOfClass:
方法的作用是判斷是否是這個(gè)類的實(shí)例筏勒,當(dāng)[[ZOCKintsugiPhotoViewController alloc] initWithPhotos:photos]
被調(diào)用時(shí),上面條件表達(dá)式的結(jié)果將會(huì)是true
旺嬉,而使用它的子類管行,上面表達(dá)式結(jié)果將返回false
。這樣 使用[self isMemberOfClass:ZOCKintsugiPhotoViewController.class]
可以 防止子類中重載初始化方法邪媳,避免無限遞歸捐顷。self = nil
的目的是移除ZOCKintsugiPhotoViewController
實(shí)例上的所有引用,實(shí)例(抽象類的實(shí)例)本身將會(huì)解除分配( 當(dāng)然ARC也好MRC也好dealloc都會(huì)發(fā)生在Main Runloop這一次的結(jié)束時(shí))雨效。接下來的邏輯就是判斷哪一個(gè)私有子類將被初始化迅涮。
最后,不管是在iPhone上還是在iPad上设易,我只需使用類似下面的代碼逗柴,而不用管具體用的是哪個(gè)子類。
NSArray *photos = @[];
ZOCKintsugiPhotoViewController *photoViewVC = [[ZOCKintsugiPhotoViewController alloc] initWithPhotos:photos];
NSLog(@"photoViewVC:%@",photoViewVC);
例如顿肺,我在iPhone下運(yùn)行戏溺,輸出的類名是 ZOCKintsugiPhotoViewController_iPhone
另外,還有幾篇篇關(guān)于類簇寫得不錯(cuò)的博文屠尊,可以幫助我們更深層次的加強(qiáng)理解,有興趣的可以去看下:
- sunnyxx 的 從NSArray看類簇
- Limboy的 類簇在iOS開發(fā)中的應(yīng)用
- 一個(gè)iOS菜菜的白話文記錄 - Class Cluster 類簇