美文网首页
高效编写代码的方法(七):类簇

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

作者: 蜂猴 | 来源:发表于2016-04-28 17:31 被阅读177次

    类簇模式

    举个例子,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,我想在理解了类簇的原理之后都能知道为什么。

    写类簇的注意<span id="jump">类簇的注意</span>

    • 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 写类簇的注意

    相关文章

      网友评论

          本文标题:高效编写代码的方法(七):类簇

          本文链接:https://www.haomeiwen.com/subject/hyrhrttx.html