高效编写代码的方法(七):类簇

类簇模式

举个例子,UIButton类的一个类方法:

+ (instancetype)buttonWithType:(UIButtonType)buttonType;

这个方法可以帮助我们“生产”出不同样式的button。
如果我们只有一个button类,要实现上面那个buttonWithType方法,可能就需要在drawRect方法中做一些判断:

- (void)drawRect:(CGRect)rect{
    if(_type == TypeA){
        //Draw TypeA Button
    }
    else if(_type == TypeB){
        //Draw TypeB Button
    }
    //..........
}

这样的方式显得非常笨重,如果不知drawRect方法要求对类型做判断,还有很多别的方法内要求判断,那么会显得非常麻烦。这种情况下,使用类簇会非常适合,不会暴露多余的接口,方法的实现也比较灵活。

创建一个类簇

创建时类簇的写法大致如下:

#import "TestButton.h"

@interface TypeAButton:TestButton

@end

@implementation TypeAButton

@end

@interface TypeBButton : TestButton

@end

@implementation TypeBButton

@end

@implementation TestButton
- (instancetype)initWithButtonType:(TestButtonType)type
{
    switch (type) {
        case ButtonTypeA:
            return [TypeAButton new];
            break;
        case ButtonTypeB:
            return [TypeBButton new];
        default:
            return [TestButton new];
    }
}

当我们进行类型判断的时候,还是要多加注意。在这种情况下isMemberOfClass可能永远不会成立,测试代码如下:

TestButton *newButton = [TestButton testButtonWithType:ButtonTypeA];
    if ([newButton isKindOfClass:[TestButton class]]) {
        NSLog(@"YES,it is kind of TestButton Class");
    }
    else{
        NSLog(@"NO");
    }
    
    if ([newButton isMemberOfClass:[TestButton class]]) {
        NSLog(@"YES,it is member of TestButtonClass");
    }
    else{
        NSLog(@"NO");
    }
打印结果

系统中的类簇

大部分的集合类型都是采用类簇模式,比如NSArray及可变版本NSMutableArray。所以有两个基本的抽象类,一个是不可变数组类,另一个是可变数组类。他们依然属于类簇,不过两个基本抽象类都暴露在了interface中。
不可变的那个类定义了数组的所有通用方法,可变的类只定义了可变数组可以调用的方法。这样的好处在于,这两个类背后可以有大量相同的代码可以复用,也可以方便进行可变拷贝和不可变拷贝。

在实际数组的创建过程中,比如

NSArray *array = [NSArray alloc] init];

实际上并不是创建了一个NSArray类,而是一个placeholder array 被创建,这个placeholder array之后会被转换为NSArray类簇中一个具体的类。
所以以下if代码,永远都不会进入:

 NSArray *testArray = [[NSArray alloc] init];
    if ([testArray class] == [NSArray class]) {
        NSLog(@"YES");
    }

所以判断类型还是使用isKindOf,我想在理解了类簇的原理之后都能知道为什么。

写类簇的注意类簇的注意

  • 1 子类必须继承自抽象的父类。比如上面代码中要写Testbutton中这个类簇的子类,那么父类比如是TestButton,而不能是TypeBButton或TypeAButton。
  • 2 父类中的声明的关键方法,子类中必须要写相应方法的实现。
  • 3 对于容器类的类簇,比如NSArray类,需要自己实现类的“储存”特性,这可能与设计初衷有点违背,因为NSArray类设计就是用来储存对象的。
    书中原话是这样:** a good choice of object to use to hold the instance of a custom array subclass would be an NSArray itself**
    不知道怎么样理解更加正确。

总结

  • 1 类簇模式可以用来隐藏一些类的实现细节。
  • 2 类簇模式在系统框架中使用的非常广泛,需要注意类别检查。
  • 3 写类簇的注意

你可能感兴趣的:(高效编写代码的方法(七):类簇)