继承工厂方法应该怎么做? [英] What should be done with inherited factory methods?

查看:169
本文介绍了继承工厂方法应该怎么做?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个类 BasicDate ,并且 BasicDate 的子类名为 EuroDate 。类别之间的差异是月 - 日 - 年与日 - 月 - 年。我知道让同一个类的方法输出它们可能会更好......但这不是这个问题的重点。

Suppose I have a class BasicDate, and a subclass of BasicDate called EuroDate. The difference between the classes is month-day-year versus day-month-year. I know it'd probably be better to just have methods on the same class to output them differently... but that's not the point of this question.

BasicDate 具有以下 init方法

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

以及匹配的工厂方法然后看起来像这样:

And the matching factory method then looks like this:

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

但如果是我的子类, EuroDate 哪个会使用工厂方法更像这样:

But if my subclass, EuroDate which would use a factory method more like this:

+(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...

这是一切都很好。现在,我们假设两个类都有自己的描述方法,这将为打印 MMDDYYYY BasicDate ,但 DDMMYYYY EuroDate 。这仍然很好。

This is all fine. Now, we assume that both classes have their own description method, which will print MMDDYYYY for BasicDate, but DDMMYYYY with EuroDate. This is still all fine.

但如果我这样做:

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

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

This will call the BasicDate factory method that EuroDate has inherited. The problem is, remember how BasicDate's factory method looks? return [[BasicDate alloc] ...]

所以今天多态转换为 BasicDate 尽管我想将它存储为 EuroDate ,所以如果我调用 description 方法,它将打印 10182013 而不是 18102013

So today polymorphs into a BasicDate despite me wanting to store it as a EuroDate, so if I call the description method, it will print 10182013 rather than 18102013.

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

There are two solutions to this problem I have found.

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

Solution 1: Change BasicDate's factory method. Rather than return [[BasicDate alloc] ..., I can instead do return [[[self class] alloc] ...] This works and will allow me to use this method for BasicDate or any of BasicDate's subclasses and it will return the right object type.

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

Solution 2: Override the factory method. Whether I override it to throw an exception or override it to do return [[EuroDate alloc] ...]. The problem with overriding it is that I have to override every factory method for every subclass.

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

Which is better? What are some downsides to the two possible solutions that I may be missing? What is considered the standard way of handling this issue in Objective C?

推荐答案

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

You should generally use [[[self class] alloc] init...] in factory methods to ensure that they create instances of the correct class. Note that class isn't a property (and in fact, there's no such thing as a 'class property') so the use of dot syntax there is inappropriate.

编辑

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

And as pointed out by @ArkadiuszHolko (and Rob, thanks), you should now use instancetype rather than id for the return value, to get the benefits of strong typing while maintaining type flexibility for subclasses. And by the way, Apple's naming conventions suggest avoiding using the word 'and' in method names. So consider rewriting your convenience method like so:

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

这篇关于继承工厂方法应该怎么做?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆