52个有效方法(9) - 以“类族模式”隐藏实现细节
2018-08-29 本文已影响7人
SkyMing一C
“类族”(class cluster)是一种很有用的模式(pattern),可以隐藏“抽象基类”(abstract base class)背后的实现细节。
Objective-C的系统框架中普遍使用此模式。
比如UIKit中就有一个名为UIButton的类,创建按钮,则可以调用下面这个类方法:
+ (UIButton *)buttonWithType:(UIButtonType)type;
//UIButtonType的枚举类型
typedef NS_ENUM(NSInteger, UIButtonType) {
UIButtonTypeCustom = 0, // no button type
UIButtonTypeSystem NS_ENUM_AVAILABLE_IOS(7_0), // standard system button
UIButtonTypeDetailDisclosure,
UIButtonTypeInfoLight,
UIButtonTypeInfoDark,
UIButtonTypeContactAdd,
UIButtonTypePlain API_AVAILABLE(tvos(11.0)) API_UNAVAILABLE(ios, watchos), // standard system button without the blurred background view
UIButtonTypeRoundedRect = UIButtonTypeSystem // Deprecated, use UIButtonTypeSystem instead
};
该方法所返回的对象,其类型取决于传入的按钮类型,然而不管返回什么类型的对象,他们都继承同一个基类:UIButton,这么做的意义在于:UIButton类的使用者无需关心创建出来的按钮具体属于哪个子类,也不用考虑按钮的绘制方式等实现细节。
“类族模式”可以灵活应对多个类,将他们的实现细节隐藏在抽象基类后面,以保持接口简洁,用户无需自己创建子类实例,只需调用基类方法来创建即可。
创建类族
首先定义一个基类
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSUInteger, EOCEmployeeType) {
EOCEmployeeTypeDevlopers,
EOCEmployeeTypeProducters,
EOCEmployeeTypeTesters,
};
@interface EOCEmployee : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSUInteger salary;
// 创建对象
+(EOCEmployee *)employeeWithType : (EOCEmployeeType)type;
// 让对象做工作
- (void)doADaysWork;
@end
#import "EOCEmployee.h"
#import "EOCEmployeeTypeDevloper.h"
#import "EOCEmployeeTypeProducter.h"
#import "EOCEmployeeTypeTester.h"
@implementation EOCEmployee
+(EOCEmployee *)employeeWithType : (EOCEmployeeType)type {
switch (type) {
case EOCEmployeeTypeDevlopers:
return [EOCEmployeeTypeDevloper new];
break;
case EOCEmployeeTypeProducters:
return [EOCEmployeeTypeProducter new];
break;
case EOCEmployeeTypeTesters:
return [EOCEmployeeTypeTester new];
break;
}
}
- (void)doADaysWork {
// Subclasses implement this.
}
@end
每个“实体子类”都继承基类
@interface EOCEmployeeDeveloper : EOCEmployee
@end
@implementation EOCEmployeeDeveloper
- (void)doADaysWork {
[super doADaysWork];
NSLog(@"%@",[[self class] description]);
}
@end
github_Demo
注意:如果对象所属的类位于某个类族中,那么在查询类型信息是就要当心了,你可能觉得自己创建了某个类的实例,然而实际上创建的确实其子类的实例。在Employee这个例子中, [employee isMemberOfClass:[EOCEmployee class]]似乎会返回YES,但是发回的确实NO,因为employee并非Employee类的实例,而是其某个子类的实例。
isKindOfClass与isMemberOfClass的区别
-
- (BOOL)isKindOfClass:(Class)aClass;
确定一个对象是否是该类的实例,或者是该类子类的实例
-
- (BOOL)isMemberOfClass:(Class)aClass;
确定一个对象是否是当前类的实例。
要点
-
类族模式可以把实现细节隐藏在一套简单的公共接口后面。
-
系统框架中经常使用到类族。
-
从类族的公共抽象基类中继承子类时要当心,若有开发文档,则应首先阅读。