“类族”是一种很有用的模式,可以隐藏“抽象基类”背后的实现细节,OC系统框架中普遍使用此模式。比如UIKit中就有一个名为UIButton的类,创建按钮,则可以调用下面这个类方法:
+ (UIButton *)buttonWithType:(UIButtonType)type;
该方法所返回的对象,其类型取决于传入的按钮类型,然而不管返回什么类型的对象,他们都继承同一个基类:UIButton,这么做的意义在于:UIButton类的使用者无需关心创建出来的按钮具体属于哪个子类,也不用考虑按钮的绘制方式等实现细节。
我们可以把按钮的绘制逻辑都放在一个类里,并根据按钮类型来切换:
- (void)drawRect:(CGRect)rect {
if (_type == TypeA) {
// Draw TypeA button
} else if (_type == TypeB) {
// Draw TypeB button
}
}
这样写现在看上去还算简单,然而,若是需要依据按钮类型来切换的绘制方法有很多种,那么久麻烦了。很多优秀的程序员会将这种代码重构为多个子类,把各种按钮所用的绘制方法放到相关的子类中,不过,这么做需要用户知道各个子类才行,此时应该使用”类族模式“。
“类族模式”可以灵活应对多个类,将他们的实现细节隐藏在抽象基类后面,以保持接口简洁,用户无需自己创建子类实例,只需调用基类方法来创建即可。
创建类族
废话不多说,直接举个例子:
typedef NS_ENUM(NSUInteger, CWGEmployeeType) {
CWGEmployeeTypeDeveloper,
CWGEmployeeTypeDesigner,
CWGEmployeeTypeFinance,
}
@interface CWGEmployee : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSUInteger salary;
// 创建对象
+(CWGEmployee *)employeeWithType : (CWGEmployeeType)type;
// 让对象做工作
- (void)doADaysWork;
@end
@implementation CWGEmployee
+(CWGEmployee *)employeeWithType : (CWGEmployeeType)type {
switch (type) {
case CWGEmployeeTypeDeveloper:
return [CWGEmployeeDeveloper new];
break;
case CWGEmployeeTypeDesigner:
return [CWGEmployeeDesigner new];
break;
case CWGEmployeeTypeFinance:
return [CWGEmployeeFinance new];
break;
}
}
- (void)doADaysWork {
// Subclasses implement this.
}
@end
每个“实体子类”都继承基类,例如:
@interface CWGEmployeeDeveloper : CWGEmployee
@end
@implementation CWGEmployeeDeveloper
- (void)doADaysWork {
[self writeCode];
}
@end
```
在这个例子中,基类实现了一个“类方法”,该方法根据待创建的雇员类别分配好对应的雇员类实例。这种“工厂模式”是创建类族的办法之一。
还有一点需要注意:`如果对象所属的类位于某个类族中,那么在查询类型信息是就要当心了,你可能觉得自己创建了某个类的实例,然而实际上创建的确实其子类的实例。在Employee这个例子中, [employee isMemberOfClass:[CWGEmployee class]]似乎会返回YES,但是发回的确实NO,因为employee并非Employee类的实例,而是其某个子类的实例。`
###总结:
- 类族模式可以吧实现细节隐藏在一套简单的公共接口后面。
- 系统框架中经常使用类族。
- 从类族的公共抽象基类中基础子类是要当心,若是有开发文档,则应该首先阅读。