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