简体   繁体   English

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

[英]how can I use an Objective-C factory method in a superclass, when instantiating a subclass?

This question is about subclassing a class that has a factory method. 这个问题是关于子类化具有工厂方法的类。 I can't get the subclass to work properly. 我无法使子类正常工作。

I have a class Car. 我有一班车。 I want it to return a Car instance only if it is capable of making a trip of a specified distance, given also its fuel consumption and fuel capacity. 考虑到它的油耗和燃料容量,我希望它在能够执行指定距离的行程时才返回Car实例。 I made a class (factory) method for this. 我为此做了一个类(工厂)方法。

It does exactly what I want when I call the factory method from my view controller to instantiate a car (code is shown further down). 当我从视图控制器中调用factory方法实例化汽车时,它恰好实现了我想要的(代码显示在下面)。

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

Now I need to have trucks also, for which I need to keep track of their cargo capacity. 现在,我还需要有卡车,需要跟踪它们的载货量。 I made Truck a subclass of Car. 我将卡车定为汽车的子类。

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

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

In my view controller I can instantiate a car just fine: 在我的视图控制器中,我可以实例化一辆汽车:

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.

But a truck gets me 但是卡车把我救了

A) a compiler warning A)编译器警告

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

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

Same thing if I change Car to Truck, like this: 如果我将“汽车”更改为“卡车”,也是如此:

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

B) AND a crash when trying to access truck1.cargoCapacityLbs B)和尝试访问truck1.cargoCapacityLbs时发生崩溃

cargoCapacityLbs ..unrecognized selector sent to instance <....>**

I think there is something fundamental I am not understanding about subclassing. 我认为关于子类化我不了解一些基本知识。 I've tried calling the factory method directly in the Truck initialization method, no luck. 我试过直接在Truck初始化方法中调用factory方法,但是不走运。

I am thinking of rewriting the Car class, to not use a factory method, but that seems bad because then the validation can't be done in the Car class, and would have to be done in the view controller. 我正在考虑重写Car类,以不使用工厂方法,但这似乎很糟糕,因为那样一来,验证就无法在Car类中完成,而必须在视图控制器中完成。

Any suggestions? 有什么建议么?

A) Your approach of using factory method is legitimate and should work properly. A)您使用工厂方法的方法是合法的,应该可以正常工作。 To get rid of compiler warning, use instancetype as result type in the factory method declaration: 要摆脱编译器警告,请在工厂方法声明中使用instancetype作为结果类型:

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

B) From your code above, you should be able access cargoCapacityLbs without crashing (perhaps you've just misspelled the name?). B)从上面的代码中,您应该能够访问cargoCapacityLbs而不会崩溃(也许您只是拼错了名称?)。 Here's the code I've used and it worked properly: 这是我使用过的代码,它可以正常工作:

@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);

Instancetype did it. 实例类型做到了。 But I wasn't very happy with having 但是我对拥有

 Car *goodCar = [[self alloc] init];

in the factory method. 在工厂的方法。

I also came across this blog post http://ernstsson.net/post/80915338055/objective-c-class-factory-methods 我还遇到了此博客文章http://ernstsson.net/post/80915338055/objective-c-class-factory-methods

So I changed Car: 所以我换了车:

@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];        
}
}

Now there's no more reference to the Car class in the factory method. 现在,在工厂方法中不再有对Car类的引用。

(Couldn't post this as a comment, it's too long) (无法将其发布为评论,太长了)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM