继承工厂方法应该怎么做?

时间:2013-10-18 14:08:27

标签: objective-c inheritance polymorphism

假设我有一个类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,它会为MMDDYYYY打印BasicDate,但DDMMYYYYEuroDate。这仍然很好。

但如果我这样做:

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

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

today多变形为BasicDate,尽管我想将其存储为EuroDate,因此如果我调用description方法,则会打印10182013而不是18102013

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

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

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

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

1 个答案:

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