Objective C - 根据类型从基类创建具体的类实例

时间:2012-07-03 21:00:09

标签: objective-c ios oop

举一个现实世界的例子,假设基类是Vehicle,具体类是TwoWheeler和FourWheeler。现在车辆的类型 - TwoWheeler或FourWheeler,由基类车辆决定。当我使用alloc-init方法创建TwoWheeler / FourWheeler的实例时,它调用下面的超级实现来设置Vehicle类中定义的公共属性的值,并且在这些属性中,其中一个是实际决定类型的类型是TwoWheeler或FourWheeler。

   if (self = [super initWithDictionary:dict]){
     [self setOtherAttributes:dict]; 
      return self; 
    }

现在,当我收到一些车辆时,其中一些可能是TwoWheeler而其他人则是FourWheeler。因此,我不能像这样直接创建TwoWheeler或FourWheeler的实例

Vehicle *v = [[TwoWheeler alloc] initWithDictionary:dict];

有什么方法可以创建基类实例,一旦我知道了类型,就根据类型创建子类的实例并返回它。使用当前的实现,它将导致无限循环,因为我从具体类调用超级实现。

当我不知道事先应该实例化哪个具体类时,处理这种情况的完美设计是什么?

2 个答案:

答案 0 :(得分:5)

通常,这是通过Factory完成的。

如果您希望工厂成为基类的一部分,那很好,但可能会在将来引起问题。在Objective C中,类方法是很好的工厂。

+ (Vehicle *)vehicleWithDictionary:(NSDictionary *)dict
{
    if ([[dict objectForKey:kVehicleType] isEqualToString:@"TwoWheeler"]) {
        return [[[TwoWheeler alloc] initWithDictionary:dict] autorelease];
    } else if ([[dict objectForKey:kVehicleType] isEqualToString @"FourWheeler"]) {
        return [[[FourWheeler alloc] initWithDictionary:dict] autorelease];
    } else {
        return [[[Vehicle alloc] initWithDictionary:dict] autorelease];
    }
}

工厂可以是Vehicle类的一部分并按原样使用。

// Instead of [[Vehicle alloc] initWithDictionary:dict]
Vehicle *vehicle = [Vehicle vehicleWithDictionary:dict];

<强>更新

我想出了一个方法来做所谓的事情。让它成为一个光辉的例子,说明为什么它是一个如此糟糕的想法以及为什么你永远不应该这样做。

- (id)initWithDictionary:(NSDictionary *)dict
{
    self = [super init];
    if (self) {
        // If override is in the dictionary, then it mustn't try to call the subclass.
        if (![dict objectForKey:kOverride]) {
            NSMutableDictionary *overrideDict = [NSMutableDictionary dictionaryWithDictionary:dict];
            [overrideDict setObject:@"override" forKey:kOverride];

            if ([[dict objectForKey:kVehicleType] isEqualToString:@"TwoWheeler"]) {
                [self release];
                return [[[TwoWheeler alloc] initWithDictionary:overrideDict] autorelease];
            } else if ([[dict objectForKey:kVehicleType] isEqualToString @"FourWheeler"]) {
                [self release];
                return [[[FourWheeler alloc] initWithDictionary:overrideDict] autorelease];
            }
        }

        // init as normal
    }

    return self;
}

答案 1 :(得分:2)

你应该使用抽象工厂如下所示,类Vehicle将有一个名为createInstance的方法,这个方法将有一个参数来决定创建什么,考虑一下这个例子

+ (Vehicle*) createInstance:(int)numberOfWheels
{
    if(numberOfWheels == 2)
    {
        return [[TwoWheeler alloc] init];
    }
    else
    {
        return [[FourWheeler alloc] init];
    }

    return nil;
}

你会这样称呼它

Vehicle *v = [Vehicle createInstance:2];