第9條:以“類族模式”隱藏實現(xiàn)細節(jié)
1. 類族模式
“類族”(class cluster)是一種模式(pattern)。該模式可以靈活應對多個類,將它們的實現(xiàn)細節(jié)隱藏在“抽象基類”(abstract base class)后面,以保持接口簡潔。開發(fā)者無須自己創(chuàng)建子類實例,只需調(diào)用基類方法來創(chuàng)建即可。
2. 創(chuàng)建類族
EOCEmployee頭文件:
/* 抽象基類 */
// 職員的類型
typedef NS_ENUM(NSUInteger,EOCEmployeeType) {
EOCEmployeeTypeDeveloper,
EOCEmployeeTypeDesigner,
EOCEmployeeTypeFinance,
};
@interface EOCEmployee : NSObject
/** 名字 */
@property(nonatomic,copy) NSString *name;
/** 薪水 */
@property(nonatomic,assign) NSUInteger salary;
// 工廠方法(類方法):創(chuàng)建雇員對象
+ (EOCEmployee *)emplyeeWithType:(EOCEmployeeType)type;
// 職員干自己的工作
- (void)doADaysWork;
@end
EOCEmployee實現(xiàn)文件:
#import "EOCEmployee.h"
#import "EOCEmployeeDeveloper.h"
#import "EOCEmployeeDesigner.h"
#import "EOCEmployeeFinance.h"
@implementation EOCEmployee
/* 將子類的實例的創(chuàng)建隱藏在基類的實現(xiàn)方法中 */
// 根據(jù)職員類型創(chuàng)建子類各自的實例
+ (EOCEmployee *)emplyeeWithType:(EOCEmployeeType)type{
switch (type) {
case EOCEmployeeTypeDeveloper:
return [EOCEmployeeDeveloper new];
break;
case EOCEmployeeTypeDesigner:
return [EOCEmployeeDesigner new];
break;
case EOCEmployeeTypeFinance:
return [EOCEmployeeFinance new];
break;
}
}
- (void)doADaysWork{
// 在子類的實現(xiàn)文件中各自實現(xiàn)其工作
}
@end
EOCEmployee的子類EOCEmployeeDeveloper的實現(xiàn)文件:
#import "EOCEmployeeDeveloper.h"
@implementation EOCEmployeeDeveloper
- (void)doADaysWork{
// 子類其工作的實現(xiàn)細節(jié)
[self writeCode];
}
- (void)writeCode{
NSLog(@"writeCode");
}
@end
main函數(shù):
#import "EOCEmployee.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
EOCEmployee *developer = [EOCEmployee emplyeeWithType:EOCEmployeeTypeDeveloper];
NSLog(@"%@",[developer class]);// output EOCEmployeeDeveloper
/*
* 總結(jié):
* 工廠模式
* 通過EOCEmployee類的工廠方法創(chuàng)建出來的實例是EOCEmployee類的子類的實例
*/
}
return 0;
}
3. Cocoa里的類族
系統(tǒng)框架中有許多類族,大部分collection類都是某個類族中的抽象基類。NSArray與NSMutableArray實際上有兩個抽象基類,但是仍然算是一個類族,意味著兩者在實現(xiàn)各自類型的數(shù)組時可以共用實現(xiàn)代碼,此外,還能把可變數(shù)組復制為不可變數(shù)組,反之亦然。
id maybeAnArray = /* ... */;
if ([maybeAnArray class] == [NSArray class]){// 永遠不可為真
// will nerver be hit
}
解釋:[maybeAnArray class] 所返回的類絕不可能是NSArray類本身,因為由NSArray的初始化方法所返回的那個實例所屬的類型是“隱藏在類族公共接口后面的那個內(nèi)部類型”。
要判斷出某個實例所屬的類是否位于類族之中需要用類型信息查詢方法(自省)。
如:
id maybeAnArray = /* ... */;
if (maybeAnArray isKindOfClass:[NSArray class]){
// will be hit
}
*** 向Cocoa中NSArray這樣的類族新增子類所要遵守的規(guī)則 ***
- 子類應該繼承自類族中的抽象基類。
- 子類應該定義自己的數(shù)據(jù)存儲方式。
子類必須用一個實例變量來存放數(shù)組中的對象,而NSArray本身只不過是包在其他隱藏對象外面的殼,它僅僅定義了所有數(shù)組都需具備的一些接口。對于這個自定義的數(shù)組子類來說,可以用NSArray來保存其實例。 - 子類應當覆寫超類文檔中指明需要覆寫的方法。
在類族中實現(xiàn)子類時所需遵循的規(guī)范一般都會定義基類的文檔之中,編碼前應該先看看。
要點
- 類族模式可以把實現(xiàn)細節(jié)隱藏在一套簡單的公共接口(抽象基類)后面。
- 系統(tǒng)框架中經(jīng)常使用類族。
- 從類族的公共抽象基類中繼承子類時要當心,若有開發(fā)文檔,則應首先閱讀。