2012-01-23 68 views
4

其中一个recommended principles of object-oriented programmingLiskov substitution principle:子类的行为应与其基类相同(警告:实际上这不是Liskov原理的正确描述:请参阅PS)。类继承:构造函数应该兼容吗?多重继承的情况?

是否建议它也适用于构造函数?我主要考虑Python和它的__init__()方法,但这个问题适用于任何具有继承的面向对象语言。

我在问这个问题,因为有一个子类继承一个或多个提供一些很好的默认行为的类是有用的(就像在Python中从字典继承,所以obj['key']适用于新类的对象)。然而,让子类完全像字典一样使用并不总是自然的或简单的:有时更好的是构造函数参数只与特定的用户子类相关(例如,代表一组串行端口的类可能想要像ports['usb1']作为USB端口#1的字典那样)。对于这种情况推荐的方法是什么?具有与其基类完全兼容的子类构造函数,并通过一个对象工厂函数生成实例,该函数采用简单的,用户友好的参数?或者简单地写一个类构造函数,它的参数集不能直接赋给它的基类的构造函数,但是从用户的角度来看更合理?

PS:我曲解了Liskov的原则,上面:下面斯文的评论指出一个事实,即对象子类的应该表现得像超(子类本身并没有表现得像超类的对象;特别是它们的构造函数不必具有相同的参数[签名])。

+1

@SvenMarnach:你的评论应该是被接受的答案。 –

+0

@SvenMarnach:+1:确实如此。如果你写一个答案,我会很乐意提出你的答案(请做!)。当你回答我的一个主要问题时,我也可以将其标记为已被接受。 – EOL

回答

4

根据要求,我发布了一个答案以前的评论。

在链接的维基百科文章中定义的原则是“如果S是T的子类型,那么类型T的对象可以用类型S的对象替换”。它不会读“一个子类的行为应该和它的基类相同”。考虑构造函数时,区别很重要:维基百科版本只讨论子类型的对象,而不是类型本身。对于一个对象来说,构造函数已经被调用,所以这个原则不适用于构造函数。这也是我应用它的方式,以及它在标准库中应用的方式(例如,defaultdictdict)。

多重继承中的构造函数可能无法用与语言无关的方式进行讨论。在Python中,有两种方法。如果您的继承关系图包含菱形图案,并且您需要确保所有构造函数只被调用一次,则应使用super()并遵循Raymond Hettinger的文章Python's super() considered super中的“实用建议”一节中所述的模式。如果你没有钻石(除了包括object),你也可以对所有基类构造函数使用明确的基类调用。