I have a class hierarchy:
class ParentClass:
def do_something(self):
pass # child classes have their own implementation of this
class ChildClass1(ParentClass):
def do_something(self):
class ChildClass2(ParentClass):
def do_something(self, argument_x):
class ChildClass3(ParentClass):
def do_something(self, argument_y):
There are two problems here:
method do_something() has different interfaces in subclasses: it accepts an argument in child classes 2 and 3, but has no argument in child class 1
the arguments of do_something() have different names to emphasize that they have different meanings in child classes 2 and 3. This will become clearer below, from the usage example
This is how the classes are used:
There is a factory class that returns instances:
class ChildFactory:
def get_child(self, argument):
if argument == '1':
return ChildClass1()
elif argument == '2':
return ChildClass2()
elif argument == '3':
return ChildClass3()
later in code:
...
# 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
Questions:
Are the two problems mentioned above a sign of a bad design? If so, what's the correct way to design the hierarchy?
How to write the pseudocode snippet uniformly in python? The main concern is to avoid using a huge if/else statement for each particular case, because it will double the if/else statement from ChildFactory.get_child()
解决方案
Methods with the same name and different arguments are a code smell.
"method do_something() has different interfaces in subclasses: it accepts an argument in child classes 2 and 3, but has no argument in child class 1"
You don't say why. There are two good reasons why
child class 1 has a default value.
child class 2 ignores the value.
Almost any other reason indicates that the do_something is truly different and should have a different name.
If child class 1 has a default value, then simply code a default value explicitly in the arguments to the method function.
class ChildClass1( ParentClass ):
def do_something( argument_x= None )
....
If child class 1 ignores the value, then simply ignore the value. Don't stand on your head to ignore a vlaue.
class ChildClass1( ParentClass ):
def do_something( argument_x )
return True
There's no magic about a polymorphic method function that doesn't happen to use all argument values.
"the arguments of do_something() have different names to emphasize that they have different meanings in child classes 2 and 3."
This is just bad design. You can't have the same method function with different argument names because they do different things.
Having the same method function name is just wrong. If they are different implementations of similar things, then the arguments will have essentially the same meanings.
If they actually do different things, then you don't have polymorphism, and you should not be giving these methods the same names.
When the methods in two classes do fundamentally different things -- requiring different arguments with distinct names to make that obvious -- those methods must not have the same names. The name ceases to have meaning when it doesn't describe what the method actually does.
Note
Your code, BTW, will work in Python because of duck typing. As long as the method names match, the argument types do not have to even come close to matching. However, this is really poor design because the essential differences among the methods are so huge.