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]
相同。您应该查找“指定的初始值设定项”该模式描述了如何构造子类、初始化方法和方便的构造函数(即工厂方法)。