an architecture that groups a number of private, concrete subclasses under a public, abstract superclass. (一個(gè)在共有的抽象超類下設(shè)置一組私有子類的架構(gòu))
Class cluster 是 Apple 對抽象工廠設(shè)計(jì)模式的稱呼
class cluster 的想法很簡單: 使用信息進(jìn)行(類的)初始化處理期間,會使用一個(gè)抽象類(通常作為初始化方法的參數(shù)或者判定環(huán)境的可用性參數(shù))來完成特定的邏輯或者實(shí)例化一個(gè)具體的子類。而這個(gè)"Public Facing(面向公眾的)"類,必須非常清楚他的私有子類,以便在面對具體任務(wù)的時(shí)候有能力返回一個(gè)恰當(dāng)?shù)乃接凶宇悓?shí)例。對調(diào)用者來說只需知道對象的各種API的作用即可。這個(gè)模式隱藏了他背后復(fù)雜的初始化邏輯,調(diào)用者也不需要關(guān)心背后的實(shí)現(xiàn)。
Class clusters 在 Apple 的Framework 中廣泛使用:一些明顯的例子比如 NSNumber 可以返回不同類型給你的子類,取決于 數(shù)字類型如何提供 (Integer, Float, etc...) 或者 NSArray 返回不同的最優(yōu)存儲策略的子類。
這個(gè)模式的精妙的地方在于,調(diào)用者可以完全不管子類,事實(shí)上,這可以用在設(shè)計(jì)一個(gè)庫,可以用來交換實(shí)際的返回的類,而不用去管相關(guān)的細(xì)節(jié),因?yàn)樗鼈兌甲駨某橄蟪惖姆椒ā?/p>
** 我們的經(jīng)驗(yàn)是使用類簇可以幫助移除很多條件語句。 **
一個(gè)經(jīng)典的例子是如果你有為 iPad 和 iPhone 寫的一樣的 UIViewController 子類,但是在不同的設(shè)備上有不同的行為。
比較基礎(chǔ)的實(shí)現(xiàn)是用條件語句檢查設(shè)備,然后執(zhí)行不同的邏輯。雖然剛開始可能不錯(cuò),但是隨著代碼的增長,運(yùn)行邏輯也會趨于復(fù)雜。 一個(gè)更好的實(shí)現(xiàn)的設(shè)計(jì)是創(chuàng)建一個(gè)抽象而且寬泛的 view controller 來包含所有的共享邏輯,并且對于不同設(shè)備有兩個(gè)特別的子例。
通用的 view controller 會檢查當(dāng)前設(shè)備并且返回適當(dāng)?shù)淖宇悺?/p>
@implementation ZOCKintsugiPhotoViewController
- (id)initWithPhotos:(NSArray *)photos
{
if ([self isMemberOfClass:ZOCKintsugiPhotoViewController.class]) {
self = nil;
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
這個(gè)子例程展示了如何創(chuàng)建一個(gè)類簇。
使用[self isMemberOfClass:ZOCKintsugiPhotoViewController.class]防止子類中重載初始化方法,避免無限遞歸。當(dāng)[[ZOCKintsugiPhotoViewController alloc] initWithPhotos:photos]被調(diào)用時(shí),上面條件表達(dá)式的結(jié)果將會是True。
self = nil的目的是移除ZOCKintsugiPhotoViewController實(shí)例上的所有引用,實(shí)例(抽象類的實(shí)例)本身將會解除分配( 當(dāng)然ARC也好MRC也好dealloc都會發(fā)生在Main Runloop這一次的結(jié)束時(shí))。
接下來的邏輯就是判斷哪一個(gè)私有子類將被初始化。我們假設(shè)在iPhone上運(yùn)行這段代碼并且ZOCKintsugiPhotoViewController_iPhone沒有重載initWithPhotos:方法。這種情況下,當(dāng)執(zhí)行self = [[ZOCKintsugiPhotoViewController_iPhone alloc] initWithPhotos:photos];,ZOCKintsugiPhotoViewController將會被調(diào)用,第一次檢查將會在這里發(fā)生,鑒于ZOCKintsugiPhotoViewController_iPhone不完全是ZOCKintsugiPhotoViewController,表達(dá)式[self isMemberOfClass:ZOCKintsugiPhotoViewController.class]將會是False,于是就會調(diào)用[super initWithNibName:nil bundle:nil],于是就會進(jìn)入ZOCKintsugiPhotoViewController的初始化過程,這時(shí)候因?yàn)檎{(diào)用者就是ZOCKintsugiPhotoViewController本身,這一次的檢查必定為True,接下來就會進(jìn)行正確的初始化過程。(NOTE:這里必須是完全遵循Designated initializer 以及Secondary initializer的設(shè)計(jì)規(guī)范的前提下才會其效果的!不明白這個(gè)規(guī)范的可以后退一步熟悉這種規(guī)范在回頭來看這個(gè)說明)