在实例化子类时,如何在超类中使用Objective-C工厂方法?

时间:2015-09-29 13:21:37

标签: ios objective-c initialization subclass factory-pattern

这个问题是关于对具有工厂方法的类进行子类化。我无法让子类正常工作。

我有班车。我希望它只返回一个Car实例 ,如果能够进行指定距离的旅行,还要考虑它的油耗和燃油容量。我为此制作了一个类(工厂)方法。

当我从视图控制器调用工厂方法来实例化汽车时,它完全符合我的要求(代码进一步向下显示)。

@interface Car : NSObject
@end

@implementation Car
- (instancetype) init 
  { return [super init]; }

+ (Car *) carWithFuelConsumption:(double)miles_per_gallon 
                       andGallonsInTank:(double)gallons 
                          forTripLength:(double)miles_to_go 
{
if (miles_per_gallon * gallons) > miles_to_go) {
      Car *goodCar = [[self alloc] init];
      return goodCar;
} else {
       return nil;
}

现在我还需要卡车,我需要跟踪他们的货物容量。我把卡车变成了Car的子类。

@interface Truck : Car
@property (double) cargoCapacityLbs;
@end

@implementation Truck
- (instancetype) init {
    self = [super init];
  if (self) {
    self.cargoCapacity= 2000.0;
  }
    return self;
}

在我的视图控制器中,我可以很好地实例化汽车:

Car *car1 = [Car carWith... 20 ...5 ... 60]; //5 gallons enough for 60 miles
Car *car2 = [Car carWith... 20 ...5 ... 90]; 
/// car2 is nil, 5 gallons NOT enough for 60 miles at 20 miles per gallon.

但是一辆卡车让我

A)编译器警告

 Truck *t1 = [Car carWith... 20 ...5 ... 60]; //5 gallons enough for 60 miles

**incompatible pointer types assigning to Truck from Car**

如果我将Car改为Truck,就像这样:

Truck *truck1 = [Truck carWith... 20 ...5 ... 60]; //5 gallons enough for 60 miles

B)尝试访问truck1.cargoCapacityLbs

时发生崩溃
cargoCapacityLbs ..unrecognized selector sent to instance <....>**

我认为有一些基本的东西,我不了解子类化。我试过直接在卡车初始化方法中调用工厂方法,没有运气。

我正在考虑重写Car类,不使用工厂方法,但这似乎很糟糕,因为验证不能在Car类中完成,而且必须在视图控制器中完成。

有什么建议吗?

2 个答案:

答案 0 :(得分:2)

A)您使用工厂方法的方法是合法的,应该正常工作。 要删除编译器警告,请在工厂方法声明中使用instancetype作为结果类型:

+ (instancetype) carWithFuelConsumption:(double)miles_per_gallon
                andGallonsInTank:(double)gallons
                   forTripLength:(double)miles_to_go;

B)从上面的代码中,您应该能够访问cargoCapacityLbs而不会崩溃(也许您刚刚拼错了名字?)。这是我使用的代码,它运行正常:

@interface Car : NSObject

+ (instancetype) carWithFuelConsumption:(double)miles_per_gallon
                andGallonsInTank:(double)gallons
                   forTripLength:(double)miles_to_go;
@end

@implementation Car

+ (instancetype) carWithFuelConsumption:(double)miles_per_gallon
                andGallonsInTank:(double)gallons
                   forTripLength:(double)miles_to_go
{
    if(miles_per_gallon * gallons > miles_to_go) {
        Car *goodCar = [[self alloc] init];
        return goodCar;
    } else {
        return nil;
    }
}
@end

@interface Truck : Car
@property double cargoCapacityLbs;
@end

@implementation Truck
- (instancetype) init {
    self = [super init];

    if (self) {
        self.cargoCapacityLbs = 2000.0;
    }

    return self;
}
@end


Truck* t1  = [Truck carWithFuelConsumption:5 andGallonsInTank:44 forTripLength:3];
NSLog(@"%f", t1.cargoCapacityLbs);

答案 1 :(得分:0)

Instancetype做到了。但我对

感到不满意
 Car *goodCar = [[self alloc] init];

在工厂方法中。

我也发现了这篇博文 http://ernstsson.net/post/80915338055/objective-c-class-factory-methods

所以我改变了汽车:

@interface Car
@property double burn;
@property double gallons;
@end

@implementation Car

- (instancetype) init {
  return nil; 
 ///preclude use of an incomplete initializer
 }

 - (instancetype) initWithBurn:(double)MPG andGallonsInTank:(double) gallons {

self = [super init];
if (self) {
    _burn = MPG;
    _gallons = gallons;
}
return self;
}

+ (instancetype) createWithFuelConsumption:(double)MPG andGallonsInTank:(double)Gallons forTripLength:(double) miles {

if  (MPG * Gallons < miles) {       
     return nil;
} else {        
   return [[self alloc] initWithBurn:MPG andGallonsInTank:Gallons];        
}
}

现在工厂方法中没有更多对Car类的引用。

(无法发布此评论,这太长了)