2010-05-19 70 views
0

我想初始化取決於參數初始化一個超類的子類的一個實例:INIT]作爲一個工廠方法

[[Vehicle alloc] initWithItinerary: shortWay]; // returns a bicycle 
[[Vehicle alloc] initWithItinerary: longWay]; // returns a car 

我無法找到這樣的代碼示例。我想知道在Objective C中這是不是慣用的,或者我只是沒有在正確的地方尋找。

回答

1

查看[UIButton buttonWithType:],瞭解Apple如何執行此操作的示例。它們不是使用init,而是使用基類的靜態方法來分配適當的派生類的實例。

您還可以傳遞Class對象。也許行程知道要分配的Class或類名。你可以做這樣的事情:

[[[itinerary classToAllocate] alloc] initWithItinerary:itinerary]; 

[[NSClassFromString([itinerary classNameToAllocate]) alloc] initWithItinerary:itinerary]; 

你被允許釋放自我和創造初始化一個新的對象,雖然這是很少使用。注意遞歸。

-(id) initWithItinerary:(Itinerary *)inItinerary { 
    [self release]; // super init never called - safe if you wrote super classes 
    self = [[[inItinerary classToAllocate] alloc] init]; 
    self.itinerary = inItinerary; 
    return self; 
} 
+0

我不知道你是否可以詳細說明你對遞歸的關注。 – iter 2010-05-21 04:08:55

+1

在我的最後一個例子中,基類實現了initWithItinerary。如果派生類也有這樣一個方法,並稱爲超級initWithItinerary它會循環。只要您正在尋找它,就可以輕鬆地進行設計。 – drawnonward 2010-05-21 08:45:21

6

你可以通過自定義的init方法來做到這一點,但它會很乏味(你必須調用[super init],但是然後調用[self release]等)。在Vehicle上創建類方法並將其用作工廠方法會更簡單。例如:

+ (id) vehicleWithItinerary:(id)someItinerary { 
    if ([someItinerary isAShortWay]) { 
    return [[[Bicycle alloc] initWithItinerary:someItinerary] autorelease]; 
    } else if ([someItinerary isAMediumWay]) { 
    return [[[RocketPack alloc] initWithItinerary:someItinerary] autorelease]; 
    } else if ([someItinerary isALongWay]) { 
    return [[[Car alloc] initWithItinerary:someItinerary] autorelease]; 
    } 
    return nil; 
} 
0

您可能要枚舉添加到頭文件:

typedef enum {Bike, Car, JetPack } vehicleType

這樣,你的initWithItinerary:方法可以簡單地是:

if(VehicleType == Bike) 
{ 
    //do bike stuff 
} 
else if(VehicleType == Car) 
{ 
    //do car stuff 
} 
+0

這是一個頗具創意的方法。 – iter 2010-05-21 04:07:18

1

這就是所謂的類簇。幾個Cocoa類以這種方式工作,包括NSArray和NSString。從NSArray的init方法返回的對象永遠不會是收到該消息的同一個對象。然而,可可並不常見,因爲它通常比人們想要的更復雜。基本上,你可以找出你想在初始化器中使用的實際類,創建該類的實例,釋放自己並返回其他實例。

0

爲什麼不把方法作爲「方式」的一部分,爲您提供適合路線的適當類型的車輛。例如

例如

// Somwhere before you use them. Car and Bicycle are subclasses of Vehicle 
[shortWay setAppropriateVehicleType: [Bicycle class]]; 
[longWay setAppropriateVehicleType: [Car class]]; 

// when you need a vehicle 

Vehicle* vehicle = [[[shortWay appropriateVehicleType] alloc] init]; 
+0

我的想法是調用者不需要知道它獲得了哪個實現。如果調用者想要一個特定的子類並且知道該子類,那麼只需調用[[alloc] init]就可以了。您可能想要查看工廠概念。 – iter 2010-05-21 04:06:31

+0

和我的想法一樣,調用者不知道它獲得了哪個實現。由於要返回的正確類是行程的一個屬性,因此我明顯地明確地按照我所做的那樣做。您實際選擇的答案與我的概念非常相似,因爲行程確實將班級保留爲屬性,並且最終分配該班級的對象。不同之處在於我的版本更加清晰,不依賴於類集羣。 – JeremyP 2010-05-21 07:56:51