天天看點

第五章 複合

   之前學習的繼承,繼承是在兩個類之間建立的關系的一種方式。現在我們學習類之間關系的另一種建立方式—複合。使用複合可以組合多個對象,使之分工協作。在實際的程式中,會用到同時使用繼承和複合來建立自己的類,這時非常重要的。

5.1 什麼是複合

   程式設計中的複合是将多個元件組合在一起配合使用,進而得到完成的程式。

定義:複合是通過包含作為執行個體變量的對象指針實作的。例如:

@interface Car : NSObject{

o   Chair *chair;

o   Wheel *wheel;

}

一個車Car對象,擁有一個Chair對象和一個Wheel輪子對象,也就是說Chair對象和Wheel對象通過複合的方式組成了Car對象。

注:嚴格的來講,隻有對象間的組合才能叫做複合。

5.1.1 Car程式

   一輛汽車包含了很多的部件,比如輪胎、發動機等等。我們用複合的方式在程式中來描述汽車這個對象。代碼CarParts,建立一個Tire和Engine類

5.1.2 自定義NSLog()

   通過NSLog()可以使用%@格式說明符來輸出對象。NSLog()處理%@說明符時,它會詢問參數清單中相應的對象以得到這個對象的描述。

我們定義一個Car類

·     @interface Car : NSObject{

o   Engine *engine;//發動機對象

o   Tire *tires[4];//輪胎對象四個

·     }

注:在程式init方法中,有if(self == [super init])判斷語句。其意思是:若要超類可以完成所需的一次性初始化,需要調用[super init].init傳回的值(id型資料,即泛型對象指針)描述了被初始化的對象。

5.2 存取方法

   我們使用存取方法來改進CarParts程式,使它的代碼更加的靈活。

1.定義:存取方法( accessor method )是用來讀取或改變對象特定屬性的方法。

·     setter方法:如setFillColor方法就是一個存取方法,稱為setter方法,目的是為對象中的某屬性指派。

·     修改方法:是用來改變對象狀态的方法的術語

·     getter方法:是另一種存取方法,目的是為了讀取對象中的某屬性的值。

2.修改CarParts程式的Car類,給它添加一些存取方法.

   一般的,存取方法總是成對出現的,一個設定屬性的值setter,一個讀取屬性的值getter。

·     setter方法根據它所更改的屬性的名稱來命名,如:setName,setEngine。

·     getter方法緊緊根據其傳回的屬性名稱來命名,如:engine,name。

5.2.1 設定發動機的屬性

   (1).setter和getter方法聲明

·     -(Engine*)engine;

·     -(void)setEngine:(Engine*) newEngine;

  (2).setter和getter方法實作

·     -(Engine*)engine{

return engine;

·     }

·     - (void)setEngine:(Engine *)newEngine{

engine = newEngine;

·     }

   (3).使用方法

·     Engine *engine = [Engine new];

·     [car setEngine:engine];

·     NSLog(@”%@”,[carengine]);

注:在Objective-C中所有對象間的互動都是通過指針實作的。

5.2.2 設定輪胎的屬性

  tires的存取方法比較複雜

   (1). -(void)setTire:(Tire *) tire atIndex:(int) index{

·     if(index< 0 || index > 0 ){

o   exit(1);

·     }

·     tires[index] = tire;

·     }

  (2). -(Tire *) tireAtIndex:(int) index{

·     if(index< 0 || index > 0 ){

o   exit(1);

·     }

·     return tires[index];

·     }

  (3).使用方法

·     Tire *tire = [Tire new];

·     [car setTire: tire atIndex:2];

·     NSLog(@”%@”,[car tireAtIndex:2]);

注意:tire存取方法使用了通用代碼來檢查執行個體變量tires數組索引,以保證它是有效數值。該代碼就是所謂的防禦式程式設計,它能夠在開發周期的早期發現錯誤。

5.2.3跟蹤汽車的變化

   既然我們在Car中建立了通路engine和tire的方法,我們就不需要init方法了,是以我們将init方法删除後在main()函數中重新建立他們

·     Car *car= [Car new];

·     Engine *engine = [Engine new];

·     [car setEngine:engine];

·      

·     for(int i = 0;i < 4;i++){

Tire *tire = [Tire new];

[car setTire:tire atIndex:i];

·     }

·     [car print];

5.3 擴充CarParts程式

   我們建立一個新類繼承自Engine,來擴充CarParts程式,參考代碼:CarParts

5.4複合還是繼承

   CarParts同時用到了繼承和複合,那麼什麼時候用繼承?什麼時候用複合?

·     繼承在對象間建立了“is a”(一個)的關系。

·     複合建立的則是“has a”(有一個)的關系。

不能随便用繼承和複合,一定考慮到這兩個對象的關系,然後恰到好處的使用繼承和複合。

小結

  複合是面向對象程式設計中一個非常重要的概念,我們用來建立和引用其他對象的對象

·     存取方法和複合是密不可分的。

·     兩種類型的存取方法:setter和getter

Cocoa的存取方法命名規則。注意的是對于傳回屬性值的存取方法,名稱中不能使用get這個詞。