Categories允許使用者為某個類添加新的方法(不能添加新的資料成員),而不用繼承的方式來實現。並且,即使沒有某個類的實現源碼,仍然可以這樣做。執行個體如下:
一. 例1:在不用Fraction源碼的情況下,為Fraction添加幾個數學(math)方法。
1. 代碼:
需要把之前編譯好的Fraction.o和Fraction.h放到和下面檔案的同一個目錄下,例如,這裡是FractionMath目錄。
//1. FractionMath.h
#import "Fraction.h"
@interface Fraction (Math)
-(Fraction*) add: (Fraction*) f;
-(Fraction*) mul: (Fraction*) f;
-(Fraction*) div: (Fraction*) f;
-(Fraction*) sub: (Fraction*) f;
@end
//2. FractionMath.m
#import "FractionMath.h"
@implementation Fraction (Math)
-(Fraction*) add: (Fraction*) f {
return [[Fraction alloc] initWithNumerator: numerator * [f denominator] +
denominator * [f numerator]
denominator: denominator * [f denominator]];
}
-(Fraction*) mul: (Fraction*) f {
return [[Fraction alloc] initWithNumerator: numerator * [f numerator]
denominator: denominator * [f denominator]];
}
-(Fraction*) div: (Fraction*) f {
return [[Fraction alloc] initWithNumerator: numerator * [f denominator]
denominator: denominator * [f numerator]];
}
-(Fraction*) sub: (Fraction*) f {
return [[Fraction alloc] initWithNumerator: numerator * [f denominator] -
denominator * [f numerator]
denominator: denominator * [f denominator]];
}
@end
//3. main.m
#import <stdio.h>
#import "Fraction.h"
#import "FractionMath.h"
int main( int argc, const char *argv[] ) {
// create a new instance
Fraction *frac1 = [[Fraction alloc] initWithNumerator: 1 denominator: 3];
Fraction *frac2 = [[Fraction alloc] initWithNumerator: 2 denominator: 5];
Fraction *frac3 = [frac1 mul: frac2];
// print it
[frac1 print];
printf( " * " );
[frac2 print];
printf( " = " );
[frac3 print];
printf( "\n" );
// free memory
[frac1 release];
[frac2 release];
[frac3 release];
return 0;
}
2. 編譯運行:
gcc -fconstant-string-class=NSConstantString -c main.m -I /GNUstep/System/Library/Headers
gcc -c FractionMath.m -I /GNUstep/System/Library/Headers
gcc main.o Fraction.o FractionMath.o -o main -L /GNUstep/System/Library/Libraries/ -lobjc -lgnustep-base
$ ./main.exe
1/3 * 2/5 = 2/15
3.說明:
(1) 必須將 Fraction.o和Fraction.h放在代碼的同一個目錄下,這才能引用到,否則,在連結的時候就找不到Fraction類。
二. 例2: 在C++(或Java)那樣,對類的方法可以用private/protected/public來限制類方法的訪問防屬性;然而,在object-c中,卻沒有這樣的規定(有的只是對成員變數的限制), 現在,可以用 categories 來實現這樣的功能。執行個體如下:
1. 代碼:
//1. ClassA.h
#import <Foundation/NSObject.h>
@interface ClassA: NSObject
-(void) print;
@end
//2. ClassA.m
#import "ClassA.h"
@implementation ClassA
//在.h中有聲明,這是個public方法
-(void) print {
printf( "this is a public method\n");
}
@end
// private 方法
@interface MyClass (Private)
-(void) privateMethod;
@end
@implementation MyClass (Private)
-(void) privateMethod {
printf( "this is a private method\n" );
}
@end
//3. main.m
#import <stdio.h>
#import "ClassA.h"
int main( int argc, const char *argv[] ) {
// create a new instance
ClassA *a = [[ClassA alloc] init];
[a print];
printf( "\n" );
//下面這個函數會編譯出錯,因為這個函數是在.m中聲明的,不能被外部存取,這就間接實現了private功能。
//[a privateMethod];
return 0;
}
二. 編譯運行(略)
三. 說明:
(1) 在.h中聲明的print函數可以認為是public的;
(2) 在.m中用 "@interface MyClass (Private)"方式聲明的,不能被外部存取,所以,間接的實現了private功能。
(3) 當然,可以把"private"改為其它的單詞,例如"aaaaaaa",都是可以的;
(4) 對比例一,關鍵的區別是這個聲明是在.h中聲明的,還是在.m中聲明的,如果是前者,那麼,在外部就可以訪問,本來的目就是為類擴充函數,正如例1一樣; 如果在.m中聲明,那麼,外部就訪問不到了。
(5) 從另一個角度理解,在訪問一個類的時候,需要import .h標頭檔的,如果在.h檔案中沒有相應函數的聲明,那麼,就會出現編譯錯誤了,這也很容易理解。