Objective-C複合(Compostion)——存取方法

0x01 存取方法是間接的一個例子

上一篇中,我們已經構造了一臺“車”。

假設現在我想要隨時更換自己喜歡的發動機和輪胎,就要用到“存取方法”。

“存取方法”是用來讀取或改變某個對象屬性的方法,例如此前見過的setFillColor:就是一個存取方法。

如果我們要對其他對象中的屬性進行操作,應該儘量使用對象提供的存取方法,絕對不要直接改變對象裏面的值,而應該使用setter方法進行更改。

正確使用“存取方法”將會使程序更加靈活。


0x02 方法的命名規則

1、雖然說方法的命名是自由的,但爲了程序的可讀性,我們還是應該遵循Cocoa的慣例:

setter方法應根據它所要更改的屬性名稱來命名,如“set+屬性名”;

getter方法只需以其返回的屬性名命名即可,即“屬性名”。

因爲get這個詞在Cocoa中有特殊含義,如果get出現在Cocoa的方法名稱中,就意味着這個方法會將傳遞給它的參數作爲指針來返回數值。


2、setter方法和getter方法一般是成對出現的,當然也可以不成對出現。如對於只讀特性只有getter方法,對於密碼特性只有setter方法。


0x03 存取方法的實現


我們先在Car的接口中對添加的setter和getter方法進行聲明:

@interface Car : NSObject
{
  Engine *engine;
  Tire *tires[4];
}

//New Code
- (Engine *) engine;
- (void) setEngine: (Engine *) newEngine;
- (Tire *) tireAtIndex: (int) index;
- (void) setTire: (Tire *) tire atIndex: (int) index;
//New Code

- (void) print;
@end // Car


第一對存取方法是爲了訪問發動機的屬性:

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

調用Car對象的engine方法可以訪問engine變量,調用setEngine:方法可以更改發動機屬性。

下面是這兩個方法的實現:

- (Engine *) engine
{
  return (engine);
} // engine
- (void) setEngine: (Engine *) newEngine
{
  engine = newEngine;
} // setEngine

我們看到getter方法engine返回的是一個指針,指向Car中的Engine對象。實際上是返回實例變量engine的當前值;

同樣的,setter方法setEngine:將newEngine的值賦給engine實例變量。實際上被修改的是engine的指針值。

在Objective-C中所有對象間的交互都是通過指針實現的!


第二對存取方法是爲了訪問輪胎的屬性:

- (void) setTire: (Tire *) tire atIndex: (int) index;
- (Tire *) tireAtIndex: (int) index;

由於汽車的4個輪胎處於4個位置,所以Car對象中必須包含一個表示輪胎位置的數組:

- (void) setTire: (Tire *) tire atIndex: (int) index
  {
  if (index < 0 || index > 3) {
   NSLog (@"bad index (%d) in setTire:atIndex:",index);
   exit (1);
}
  tires[index] = tire;
} // setTire:atIndex:
- (Tire *) tireAtIndex: (int) index
{
  if (index < 0 || index > 3) {
   NSLog (@"bad index (%d) in "tireAtIndex:", index);
   exit (1);
}
  return (tires[index]);
} // tireAtIndex:

因爲tire是一個C風格的數組,對於其索引值是否有效,編譯器是可能直接忽略的。所以我們自己得用if條件語句來判斷index值是否合理,這是一種防禦式編程思想

setTire:方法的聲明格式看起來不太一樣,這是因爲它擁有兩個參數,往後學習會更加理解這種寫法。


最後修改main()函數:

int main (int argc, const char * argv[]) {
  Car *car = [Car new];
  //事實上可以在Car類中把init方法刪掉,因爲下面的代碼已經做了init方法的工作

  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];
  return (0);
} // main

程序運行結果沒有變化,但我們改進了它的內部結構,使程序更加靈活:

I am an engine. Vrooom!
I am a tire. I last a while.
I am a tire. I last a while.
I am a tire. I last a while.
I am a tire. I last a while.

0x04 存取方法的應用

我們已經爲Car類添加了存取方法,那換配置就是隨心所欲的事了。

現在來爲這臺車換一個發動機:

@interface Slant6 : Engine
@end // Slant6

@implementation Slant6
- (NSString *) description
{
  return (@"I am a slant- 6. VROOOM!");
} // description
@end // Slant6

創建這臺Slant6發動機,繼承了Engine超類的屬性。但是重寫了description方法,輸出了新發動機的信息。


接着我們換輪胎:

@interface AllWeatherRadial : Tire
@end // AllWeatherRadial

@implementation AllWeatherRadial
- (NSString *) description
{
  return (@"I am a tire for rain or shine.");
} // description
@end // AllWeatherRadial


最後修改main()函數,這臺車使用了全新的發動機和輪胎:

int main (int argc, const char * argv[]) {
  Car *car = [Car new];
  for (int i = 0; i < 4; i++) 
{

   //New Code

   Tire *tire = [AllWeatherRadial new];
   //New Code
   [car setTire: tire atIndex: i];
  }

  //New Code
  Engine *engine = [Slant6 new];
  //New Code

  [car setEngine: engine];
  [car print];
  return (0);
} // main

運行程序後,可以發現輸出已經更新爲新配置了:

I am a slant- 6. VROOOM!
I am a tire for rain or shine.
I am a tire for rain or shine.
I am a tire for rain or shine.
I am a tire for rain or shine.


發佈了67 篇原創文章 · 獲贊 28 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章