假设以下类层次结构具有基类和一些继承自基类的通用案例类:
class BaseClass:
def f(self, a, b):
#do something
pass
class GeneralCase(BaseClass):
def f(self, a, b):
BaseClass.f(self, a, b)
#do something else
现在,假设我们有一个特殊情况,其中(其中)函数f
的一个参数是预定且不变的。一
实现这一点的方法是从参数列表中删除此参数,如下所示:
class SpecialCase1(GeneralCase):
def f(self, a):
Pro:干净,明确
Con's:当使用不同类的对象时,不同的方法签名可能会导致问题
选项2:设置默认值并声明它未被更改
class SpecialCase2(GeneralCase):
def f(self, a, b=PREDEFINED_VALUE):
assert b == PREDEFINED_VALUE
GeneralCase.f(self, a, PREDEFINED_VALUE)
Pro:相同的签名
Con:令人困惑的界面:“为什么我们有参数b?如果我改变它会发生什么?”
你会采取什么方法?为什么?
答案 0 :(得分:3)
它根本不应该是一个子类型(参见Liskov Substitution Principle)。
有GeneralCase
的属性,即:
有一个方法
f
有两个参数...... yadda yadda yadda
此属性应该适用于GeneralCase
的所有子类型(或者是鸭子类型,任何应该像GeneralCase
一样嘎嘎叫的东西,无论类关系如何)。如果它不成立,那么处理这些对象的所有代码都必须知道它并围绕它进行编码。这是一个不可接受的负担,而且基本上没必要。
如果某个特殊情况下该属性不正确,则该特殊情况不应为子类型。它可能是高度相关的,但要么您需要更一般的GeneralCase
,要么它不是GeneralCase
的特殊情况。
如果您想要重用代码,请使用mixins。如果有代码可以在GeneralCase
和SpecialCase
上运行(例如因为它不使用该方法),您可以定义一个不包含该方法的更通用的接口(可能含蓄地,我们不需要interface
关键字),从而避免上述麻烦。
答案 1 :(得分:0)
怎么样:
class SpecialCase2(GeneralCase):
def f(self, a, b):
GeneralCase.f(self, a, PREDEFINED_VALUE)
这样特殊情况2根本不使用b,界面保持不变。