2

假设我有一个类BasicDate和一个BasicDate被调用的子类EuroDate。类之间的区别是月-日-年与日-月-年。我知道在同一个类上使用不同的方法来输出它们可能会更好......但这不是这个问题的重点。

BasicDate有以下内容init method

-(id)initWithMonth:(int)m andDay:(int)d andYear:(int)y {
    if(self = [super init]) { /*initialize*/ } return self;
}

然后匹配factory method看起来像这样:

+(BasicDate)dateWithMonth:(int)m andDay:(int)d andYear:(int)y {
    return [[BasicDate alloc] initWithMonth: m andDay: d andYear: y];
}

但是如果我的子类,EuroDate它会使用factory method更像这样的:

+(EuroDate)dateWithDay:(int)d andMonth:(int)m andYear:(int)y {
    return [[EuroDate alloc] initWithDay: d andMonth: m andYear: y];
} //we can assume that EuroDate includes this init method...

这一切都很好。现在,我们假设两个类都有自己的description method,将打印MMDDYYYYfor BasicDate,但DDMMYYYY带有EuroDate. 这仍然很好。

但如果我这样做:

EuroDate today = [EuroDate dateWithMonth:10 andDay:18 andYear:2013];

这将调用已继承的BasicDate工厂方法。EuroDate问题是,还记得BasicDate工厂方法的样子吗? return [[BasicDate alloc] ...]

因此,尽管我想将它存储为 a ,但仍将其变形为 a today,因此如果我调用该方法,它将打印而不是.BasicDateEuroDatedescription1018201318102013

我发现这个问题有两种解决方案。

解决方案1:更改BasicDate工厂方法。而不是return [[BasicDate alloc] ...,我可以改为这样做return [[[self class] alloc] ...] 这有效,并将允许我将此方法用于BasicDate或任何子BasicDate类,它将返回正确的对象类型。

解决方案2:Override工厂方法。我是否覆盖它以引发异常或覆盖它以执行return [[EuroDate alloc] ...]. 覆盖它的问题是我必须覆盖每个子类的每个工厂方法。

哪个更好?我可能缺少的两种可能的解决方案有哪些缺点?在 Objective C 中处理这个问题的标准方法是什么?

4

1 回答 1

3

您通常应该[[[self class] alloc] init...]在工厂方法中使用以确保它们创建正确类的实例。请注意,这class不是一个属性(实际上,没有“类属性”之类的东西),因此使用点语法是不合适的。

编辑

正如@ArkadiuszHolko(和Rob,谢谢)所指出的那样,您现在应该使用instancetype而不是id返回值,以获得强类型的好处,同时保持子类的类型灵活性。顺便说一句,Apple 的命名约定建议避免​​在方法名称中使用“和”一词。因此,请考虑像这样重写您的便捷方法:

+ (instancetype)dateWithMonth:(int)month day:(int)day year:(int)year
{
    return [[self alloc] initWithMonth:month day:day year:year];
}
于 2013-10-18T14:40:32.733 回答