Objective c 使用继承的工厂方法应该做什么?

Objective c 使用继承的工厂方法应该做什么?,objective-c,inheritance,polymorphism,Objective C,Inheritance,Polymorphism,假设我有一个类BasicDate,还有一个名为EuroDate的子类BasicDate。课程之间的差异是月-日-年与日-月-年。我知道在同一个类上使用不同的方法来输出它们可能会更好。。。但这不是这个问题的重点 BasicDate具有以下init方法: -(id)initWithMonth:(int)m andDay:(int)d andYear:(int)y { if(self = [super init]) { /*initialize*/ } return self; } 匹配的工

假设我有一个类
BasicDate
,还有一个名为
EuroDate
的子类
BasicDate
。课程之间的差异是月-日-年与日-月-年。我知道在同一个类上使用不同的方法来输出它们可能会更好。。。但这不是这个问题的重点

BasicDate
具有以下
init方法

-(id)initWithMonth:(int)m andDay:(int)d andYear:(int)y {
    if(self = [super init]) { /*initialize*/ } return self;
}
匹配的
工厂方法
如下所示:

+(BasicDate)dateWithMonth:(int)m andDay:(int)d andYear:(int)y {
    return [[BasicDate alloc] initWithMonth: m andDay: d andYear: y];
}
+(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...
但是如果我的子类,
EuroDate
将使用
工厂方法
更像这样:

+(BasicDate)dateWithMonth:(int)m andDay:(int)d andYear:(int)y {
    return [[BasicDate alloc] initWithMonth: m andDay: d andYear: y];
}
+(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...
这一切都很好。现在,我们假设这两个类都有自己的
描述方法
,它将为
BasicDate
打印
MMDDYYYY
,但是
DDMMYYYY
带有
EuroDate
。这一切都很好

但如果我这样做:

EuroDate today = [EuroDate dateWithMonth:10 andDay:18 andYear:2013];
这将调用
BasicDate
已继承的
EuroDate
工厂方法。问题是,还记得
BasicDate
的工厂方法的外观吗<代码>返回[[BasicDate alloc]…]

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

我找到了两种解决这个问题的方法

解决方案1:更改基本日期的工厂方法。与其使用
return[[BasicDate alloc]…
,我可以改为使用
return[[self class]alloc]…]
这个方法,并允许我将此方法用于
BasicDate
或任何
BasicDate
的子类,它将返回正确的对象类型

解决方案2:
重写
工厂方法。无论是重写它以引发异常,还是重写它以执行
返回[[EuroDate alloc]…]
。重写它的问题是,我必须为每个子类重写每个工厂方法


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

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

编辑

正如@ArkadiuszHolko(还有Rob,谢谢)所指出的现在,您应该使用<代码> StaseCythype 而不是<代码> ID <代码>返回值,以获得强类型的好处,同时保持子类的类型灵活性。顺便说一下,Apple的命名约定建议在方法名称中避免使用“和”这个词。因此,请考虑改写您的便利方法,例如:

+ (instancetype)dateWithMonth:(int)month day:(int)day year:(int)year
{
    return [[self alloc] initWithMonth:month day:day year:year];
}

我修正了问题中的点符号。谢谢。Objective-C不是我的母语。而且,正如@ArkadiuszHolko的回答中所指出的,现在还应该在工厂方法中返回
instancetype
。在
instancetype
之前,所有工厂方法都必须返回
id
以避免警告。它应该是
返回[[BasicDate alloc]…]
还是应该是
返回[[self-alloc]…]
返回[[self-alloc]initBlah];
还是
返回[[self-class]alloc]initBlah];
?如果我使用第一个,当我继承并调用子类对象上的方法时,它会返回正确的类型吗?或者我需要在超类中使用第二个,以便子类返回正确的类型吗?@nhgrif in-methods self指方法的接收者。在类方法中,这是类,而不是实例(对象)因此,在类方法中,您可以编写
[[self alloc]initBlah]
。因此,当
self
是实际的
BasicDate
,这实际上与
[[BasicDate alloc]initBlah]
相同。您应该查找“指定的初始值设定项”该模式描述了如何构造子类、初始化方法和方便的构造函数(即工厂方法)。