我有一个类层次结构:
class ParentClass:
def do_something(self):
pass # child classes have their own implementation of this
class ChildClass1(ParentClass):
def do_something(self):
<implementation here>
class ChildClass2(ParentClass):
def do_something(self, argument_x):
<implementation here>
class ChildClass3(ParentClass):
def do_something(self, argument_y):
<implementation here>
这里有两个问题:
这是使用类的方式:
有一个返回实例的工厂类:
class ChildFactory:
def get_child(self, argument):
if argument == '1':
return ChildClass1()
elif argument == '2':
return ChildClass2()
elif argument == '3':
return ChildClass3()
稍后在代码中:
...
# pseudocode, not python
child_type = ? # can have values '1', '2' or '3' at this moment
var1 = 1
var2 = 'xxx'
# var1 and var2 have different types, just to emphasize the difference in their
# meaning when being passed as arguments to do_something()
# this was mentioned above (the second problem)
child = ChildFactory.get_child(child_type)
if child is an instance of ChildClass1, child.do_something() is called
if child is an instance of ChildClass2, child.do_something(var1) is called
if child is an instance of ChildClass3, child.do_something(var2) is called
# end of pseudocode
问题:
答案 0 :(得分:10)
具有相同名称和不同参数的方法是代码气味。
“方法do_something()在子类中有不同的接口:它接受子类2和3中的参数,但在子类1中没有参数”
你没有说明原因。
有两个很好的理由子类1具有默认值。
子类2忽略该值。
几乎任何其他原因都表明do_something
真正不同,并且应该有不同的名称。
如果子类1具有默认值,则只需在方法函数的参数中显式编写默认值。
class ChildClass1( ParentClass ):
def do_something( argument_x= None )
....
如果子类1忽略该值,则只需忽略该值。不要站在你的头上忽视一个角色。
class ChildClass1( ParentClass ):
def do_something( argument_x )
return True
没有使用所有参数值的多态方法函数没有魔力。
“do_something()的参数具有不同的名称,以强调它们在子类2和3中具有不同的含义。”
这只是糟糕的设计。您不能使用具有不同参数名称的相同方法函数,因为它们执行不同的操作。
具有相同的方法函数名称是错误的。如果它们是类似事物的不同实现,那么参数将具有基本相同的含义。
如果他们实际上做了不同的事情,那么你就没有多态性,你不应该给这些方法赋予相同的名称。
当两个类中的方法做了根本不同的事情 - 需要使用不同名称的不同参数来表明这些 - 这些方法必须具有相同的名称。当该名称没有描述该方法的实际用途时,该名称就不再具有意义。
注意强>
你的代码,BTW,因为鸭子打字,将在Python中运行。只要方法名称匹配,参数类型就不必接近匹配。然而,这是非常糟糕的设计,因为这些方法之间的本质区别是如此巨大。
答案 1 :(得分:2)
这样的抽象问题很难回答。如果我们知道你试图解决什么问题,那么回答会容易得多。我可以告诉你,通常看到类似的东西是不好的迹象:
if isinstance(obj, cls1):
...
elif isinstance(obj, cls2):
...
通常,这意味着您应该定义一个新方法而不是使用if / elif。在Python中,如果您愿意,可以在类定义之外定义方法,如果这有帮助的话。如果两个可互换的类具有相同名称的方法但采用不同数量的参数,则通常也是一个不好的标志,这意味着这些类不是真正可互换的。不同的方法应该采用相同的参数,或者它们应该具有不同的名称。也没有必要定义从未调用过的方法,例如ParentClass中的do_something - 这是你从C ++ / Java / C#到Python的程序员看到的。
答案 2 :(得分:1)
如果要互换使用,它们应该具有相同的界面。对于方法,这意味着相同数量的参数具有相同的含义和相同的名称。如果它们的行为不完全相同,只需给它们不同的名称,使它们看起来可以互换。
答案 3 :(得分:-2)
你可以这样做,使签名相同:
class ParentClass:
pass
class ChildClass1(ParentClass):
def do_something(self, **kwargs):
<implementation here>
class ChildClass2(ParentClass):
def do_something(self, **kwargs):
argument_x = kwargs[argument_x]
<implementation here>
class ChildClass3(ParentClass):
def do_something(self, **kwargs):
argument_y = kwargs[argument_y]
<implementation here>
工厂可能只是一个字典:
childfactory = {1:ChildClass1, 2:ChildClass2, 3:ChildClass3}
然后:
...
# pseudocode, not python
child_type = ? # can have values '1', '2' or '3' at this moment
var1 = 1
var2 = 'xxx'
# var1 and var2 have different types, just to emphasize the difference in their
# meaning when being passed as arguments to do_something()
# this was mentioned above (the second problem)
child = childfactory[child_type]()
child.do_something(argument_x=val1, argument_y=var2)
# end of pseudocode