如何對類簇進行子類化

本文的內容主要來源于 Friday Q&A 2010-03-12: Subclassing Class Clusters by Mike Ash,部分內容有增補和調整。

抽象類 - Abstract Class

要給一個類簇創(chuàng)建的子類,需要先知道類簇是什么。而要理解類簇,需要首先理解抽象類(Abstract Class)的概念。

抽象類是一個沒有實現全部功能的類,它需要被子類化,由子類實現抽象類缺少的功能。抽象類不一定是個徹底的空殼,它依然可以包含很多功能,但只有在子類實現了抽象類沒有實現的功能后,這個類才是完整的。

類簇 - Class Cluster

類簇(Class Cluster)是一個繼承自公共抽象(基)類的層次結構。這個公共類提供了統一的接口和許多輔助功能,而核心功能由私有的子類來實現。公共類提供的實例化方法會返回私有子類的實例,使用戶可以在不需要了解這些子類的情況下使用公共類。

例如,NSArray就是一個抽象類,需要其子類提供countobjectAtIndex:這兩個方法的實現。抽象類NSArray提供了各種構建在這兩者之上的方法,例如indexOfObject: ,objectEnumerator , makeObjectsPerformSelector:等等。

NSArray的核心功能由私有子類(如NSCFArray) 實現。NSArray的實例化方法如+arrayWithObjects:-initWithContentsOfFile:生成的是這些私有子類的實例。

從外部來看, 一般不容易發(fā)現NSArray是一個類簇。但是在對類對象進行自?。╥ntrospection)時(例如使用isKindOfClass:方法),可能會發(fā)現你得到的不是一個NSArray,而是一個NSCFArray或者別的子類;或者在調試時可能會發(fā)現雖然你創(chuàng)建了一個NSArray,但是調試信息上顯示的是NSCFArray。除此之外,NSArray的行為常常與其他任何類一樣,看不出什么特別的。

而在一種特定的情況下類簇的性質非常重要,那就是你自己將公共類子類化。

子類化 - Subclassing

對類簇進行子類化(這意味著對抽象類進行子類化)與子類化一個普通類完全不同。

子類化一個普通類時,超類已經提供了完整的功能。在這種情況下,子類可以不需要實現任何的方法,就已經是一個完全可用的類,此時它的行為與超類一樣。然后,你可以根據需求為這個子類添加其他方法或覆蓋現有方法。

當繼承一個類簇時,超類不提供完整的功能。它提供了許多輔助功能,但你必須自己提供核心功能。這意味著,一個空的子類是無效的。你至少需要實現幾個必要的方法。在關于類簇的術語中,必須實現的那些方法稱為基本方法(primitive methods)。有兩種簡單的途徑確定哪些方法是基本方法。

第一種途徑是查看類簇的文檔,在其中查看 "Subclassing Notes" 搜索單詞 "primitive",文檔會告訴你需要覆蓋(override)哪些方法。

第二種途徑是打開類簇的頭文件。原始方法會在類的主@interface塊中聲明。類簇提供的其他方法則會在分類(categories)中聲明。

如果一個類簇本身是另一個類簇的子類,那你要多加小心。因為你需要實現這兩個類簇所有的原始方法。例如,NSMutableArray本身有五個原始方法,它的超類NSArray有兩個。如果你要子類化NSMutableArray,則必須為所有七個方法提供實現。

- Techniques

現在知道了要實現什么,但是如何實現?主要有三種方式。

方法一,你可以自己從頭實現每個原始方法。舉個例子,假設要編寫一個專門用于保存兩個元素的數組:

    @interface MyPairArray : NSArray {
        id _objs[2];
    }

    - (id)initWithFirst:(id)first second:(id)second;

    @end
    
    @implementation MyPairArray
    
    - (id)initWithFirst:(id)first second:(id)second
    {
        if((self = [self init])) {
            _objs[0] = first;
            _objs[1] = second;
        }
        return self;
    }
    
    - (NSUInteger)count {
        return 2;
    }
    
    - (id)objectAtIndex: (NSUInteger)index {
        if(index >= 2)
            [NSException raise: NSRangeException format: @"Index (%ld) out of bounds", (long)index];
        return _objs[index];
    }
    @end

當然,嚴格來講,如何實現原始方法取決于你希望它們做什么。以上只是個例子,通過使用一個C數組實現了MyPairArray的功能。

方法二,你可以內置一個工作實例(working instance),并把對你的調用傳遞給它來處理:

    @interface MySpecialArray : NSArray

    @property (copy, nonatomic) NSArray *_realArray;
    
    - (id)initWithArray: (NSArray *)array;
    
    @end
    
    @implementation MySpecialArray
    
    - (id)initWithArray: (NSArray *)array {
        if((self = [self init])) {
            _realArray = [array copy];
        }
        return self;
    }
        
    - (NSUInteger)count {
        return [_realArray count];
    }
    
    - (id)objectAtIndex: (NSUInteger)index {
        id obj = [_realArray objectAtIndex: index];
        // do some processing with obj
        return obj;
    }
    
    // maybe implement more methods here
    @end

這種方法允許你重用原始方法的現有實現,然后添加更多功能。

方法三,給類簇添加一個分類(category),而不對其進行子類化。有時候只是需要添加新方法,而不需要修改現有功能。在Objective-C中,你可以在分類中添加新方法:

    @interface NSArray (FirstObjectAdditions)
    
    - (id)my_firstObject;
    
    @end
    
    @implementation NSArray (FirstObjectAdditions)
    
    - (id)my_firstObject {
        return [self count] ? [self objectAtIndex: 0] : nil;
    }
    
    @end

(這個方法名添加了前綴,以防與官方提供的方法造成沖突。)

結論 - Conclusion

類簇與普通類有所不同,但一旦理解了它們的含義,就很容易進行子類化。你需要實現類簇的基本方法 ,可以自己實現也可以通過內置一個類簇的實例來實現。最后,如果你創(chuàng)建子類的唯一目的是添加新方法,請改用分類來實現。

擴展閱讀
類簇-官方文檔

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 類簇 在官方文檔中的解釋 官方文檔中的解釋 以下是翻譯 類簇 類簇是Foundation框架廣泛使用的設計模式。類...
    伯陽閱讀 696評論 0 2
  • 設計模式概述 在學習面向對象七大設計原則時需要注意以下幾點:a) 高內聚、低耦合和單一職能的“沖突”實際上,這兩者...
    彥幀閱讀 3,888評論 0 14
  • 禪與 Objective-C 編程藝術 (Zen and the Art of the Objective-C C...
    GrayLand閱讀 1,781評論 1 10
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,666評論 1 32
  • 不同季節(jié)的雨有不同的特色。春天的雨綿延,夏天的雨傾盆,秋天的雨涼爽,冬天的雨冰冷。 下面我就來...
    馬瀅爸爸閱讀 252評論 0 2

友情鏈接更多精彩內容