编写高质量代码的52个有效方法

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的区别
要点
  1. 类族模式可以把实现细节隐藏在一套简单的公共接口后面。

  2. 系统框架中经常使用到类族。

  3. 从类族的公共抽象基类中继承子类时要当心,若有开发文档,则应首先阅读。

上一篇 下一篇

猜你喜欢

热点阅读