在上一篇博文中,咱們將原先的純C語言代碼,編寫成了用Objective-C(後面直接縮寫成OC)的寫法。使得代碼在易讀性上有明顯提高,結構也更清晰。同時,也對面向對象的概念有了進一步的介紹和加深。框架
可是,經過上一個例子,咱們發現代碼的冗餘仍是很大。像Circle,Rectangle和Egg的定義和實現方法幾乎代碼都是基本相同,只有個別地方不一樣。那麼,有什麼好方法來優化這些代碼呢?今天這篇博文的重點就是要介紹繼承這個方法,它將會有效的解決上面說的這個問題。函數
正如你從親生父母那裏繼承一些特性(頭髮的顏色,鼻子的形狀等)同樣,面向對象中的繼承代表一個類從另一個類——它的父類或超類(另外一種叫法)中獲取了某些特性。也就是說,Circle,Rectangle和Egg是從Shape類繼承而來的,所以它們將得到Shape類的屬性。優化
那麼,首先先給你們介紹下,在OC中,繼承的語法格式。其實,在以前幾篇博文中已經看到。聲明一個類的時候,@interface Circle :NSObject。這裏的冒號,就是繼承的標示符,冒號後面的NSObject就是要繼承的類,也就是說是父類(使用Cocoa框架的時候,要繼承)。注:在OC中,不支持多繼承。spa
好了,介紹了基本的繼承的知識。接下來,咱們就開始動手修改代碼吧。咱們的思路是:先定義一個總的Shape父類,定義好方法和屬性,而後繼承父類。code
1 #import <Foundation/Foundation.h> 2 /* 1. enum 枚舉類型 */ 3 //定義繪製圖形的類型: 圓形,矩形,橢圓形 4 typedef enum{ 5 kCircle, 6 kRectangle, 7 kEgg 8 } ShapeType; 9 10 //定義繪製圖形的顏色: 紅色,綠色和藍色 11 typedef enum{ 12 kRedColor, 13 kGreenColor, 14 kBlueColor 15 } ShapeColor; 16 17 /* 2. struct 結構體 */ 18 //定義圖形的基本屬性 19 typedef struct{ 20 int x, y, width, height; 21 } ShapeRect; 22 23 NSString *colorName (ShapeColor fillColor) 24 { 25 switch(fillColor) 26 { 27 case kRedColor: 28 return @"red"; 29 break; 30 case kGreenColor: 31 return @"green"; 32 break; 33 case kBlueColor: 34 return @"blue"; 35 break; 36 } 37 } 38 39 /* 3. 定義Shape父類*/ 40 @interface Shape: NSObject{ 41 ShapeColor fillColor; 42 ShapeRect bounds; 43 } 44 -(void) setFillColor:(ShapeColor) fillColor; 45 -(void) setBounds:(ShapeRect) bounds; 46 -(void) draw; 47 @end //Shape 48 49 /* 實現Shape父類 */ 50 @implementation Shape 51 -(void) setFillColor:(ShapeColor) c 52 { 53 fillColor = c; 54 } 55 -(void) setBounds:(ShapeRect) b 56 { 57 bounds = b; 58 } 59 -(void) draw{ 60 } 61 @end
雖然draw方法什麼功能也沒實現,可是仍是須要定義。以便Shape的全部子類能夠經過它去實現各自的方法。對象
而後,咱們分別定義Circle,Rectangle和Egg子類:blog
1 /*定義Circle,繼承Shape父類*/ 2 @interface Circle: Shape 3 @end 4 5 /*定義Rectangle,繼承Shape父類*/ 6 @interface Rectangle: Shape 7 @end 8 9 /*定義Egg,繼承Shape父類*/ 10 @interface Egg: Shape 11 @end
接下來,對子類的draw方法進行實現,代碼以下:繼承
1 @implementation Circle 2 -(void) draw 3 { 4 NSLog(@"drawing a circle at (%d %d %d %d) in %@", 5 bounds.x, 6 bounds.y, 7 bounds.height, 8 bounds.width, 9 colorName(fillColor)); 10 } 11 @end 12 13 @implementation Rectangle 14 -(void) draw 15 { 16 NSLog(@"drawing a rectangle at (%d %d %d %d) in %@", 17 bounds.x, 18 bounds.y, 19 bounds.height, 20 bounds.width, 21 colorName(fillColor)); 22 } 23 @end 24 25 @implementation Egg 26 -(void) draw 27 { 28 NSLog(@"drawing an egg at (%d %d %d %d) in %@", 29 bounds.x, 30 bounds.y, 31 bounds.height, 32 bounds.width, 33 colorName(fillColor)); 34 } 35 @end
經過用繼承方法的修改,代碼冗餘問題明顯感受好了不少。Main() 主函數則徹底不用修改,就能夠運行,運行結果和以前的同樣:ci
在上面的例子中,咱們在子類中從新實現了draw的方法,這個過程叫重寫方法。執行的時候,若是子類中有從新定義父類中的方法,那麼就會先去執行子類方法,父類中的同名方法則會別忽略。若是子類方法找不到,再去執行父類中定義的方法。it
在OC中,也提供了既能夠重寫方法實現,又能夠調用父類自身實現的方法。爲了調用繼承的方法在父類中出現,須要使用super做爲方法調用的目標。當咱們向super發送信息的時候,其實是請求OC向該類的父類發送消息。下面就修改一個使用super關鍵字的例子:
1 @implementation Circle 2 -(void) setFillColor:(ShapeColor) c 3 { 4 if(c == kRedColor) 5 { 6 c = kGreenColor; 7 } 8 [super setFillColor: c]; 9 } 10 -(void) draw 11 { 12 NSLog(@"drawing a circle at (%d %d %d %d) in %@", 13 bounds.x, 14 bounds.y, 15 bounds.height, 16 bounds.width, 17 colorName(fillColor)); 18 } 19 @end
我修改了下Circle類的實現方法,對setFillColor方法進行了從新。假如調用的顏色是紅色,則返回的是綠色。在函數的結尾處,使用super關鍵字,通知父類,將新的顏色存儲在fillColor變量中。
好了,今天對繼承的介紹就先在這告一段落吧。晚安,各位!