init]作为工厂方法

时间:2010-05-19 05:51:04

标签: objective-c oop

我想根据init的参数初始化一个超类的子类的实例:

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

我找不到像这样的代码示例。我想知道这在目标C中是不是惯用的,或者我只是在寻找合适的位置。

5 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:1)

请查看[UIButton buttonWithType:]以获取Apple如何执行此操作的示例。而不是init,它们使用基类的静态方法来分配适当派生类的实例。

您还可以传递Class个对象。也许行程知道要分配的Class或类名。你可以这样做:

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

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

您可以在init中释放self并创建一个新对象,尽管很少使用它。请注意递归。

-(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;
}

答案 2 :(得分:1)

这称为类集群。几个Cocoa类以这种方式工作,包括NSArray和NSString。从NSArray的init方法返回的对象永远不是接收消息的对象。然而,在Cocoa之外并不常见,只是因为它通常比人们想要打扰更复杂。基本上,您可以确定要在初始化程序中使用的实际类,创建该类的实例,释放自己并返回另一个实例。

答案 3 :(得分:0)

您可能希望在头文件中添加枚举:

typedef enum {Bike, Car, JetPack } vehicleType

这样,您的initWithItinerary:方法可以简单地为:

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

答案 4 :(得分:0)

为什么不将方法作为“方式”的一部分,为您提供适当类型的车辆。 e.g。

e.g。

// 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];