3.3.4 多重继承与组合模式
Python语言支持多重继承,即一个子类可以同时继承多个父类,不过从项目实践角度来说多重继承会提升代码的维护成本,并很容易导致问题。在如下的MoreParentsDemo.py案例中,我们来观察一下多重继承带来的问题。
01 # coding=utf-8 02 class PrintByA3: # 打印的类,在A3纸上打印 03 def print(self): 04 print("Print File in A3.") 05 class PrintByA4: # 在A4纸上打印 06 def print(self): 07 print("Print File in A4.") 08 # 同时继承了两个类 09 # class PrintHandler(PrintByA4,PrintByA3): 10 class PrintHandler(PrintByA3,PrintByA4): 11 def handleFile(self): 12 print(self) 13 handler = PrintHandler() 14 handler.print()
在第2行和第5行里,我们分别定义了两个类,以实现在A3和A4纸上打印的功能,在其中的print方法里又分别输出了不同的语句。
在第10行的PrintHandler类里,我们分别继承了PrintByA3和PrintByA4这两个类,请注意继承的次序。在其中第11行的handleFile方法里,我们调用了父类的print方法。问题就在这里,两个父类都有print方法,这里究竟是继承了哪个?
运行上述代码,从第14行的打印语句中我们能看到“Print File in A3.”的输出,也就是说,实际继承了PrintByA3的print方法。如果这里打开第9行的注释,同时注释掉第10行的代码,让PrintHandler类继承两个类时变更继承的次序,就会看到“Print File in A4.”的输出。
从上述运行结果来看,多重继承时次序在前的类方法会覆盖掉之后的,这就会给使用带来困惑。在实际项目里,确实有类似的需求,比如在PrintHanlder类里需要同时具备在A3和A4纸上打印的功能,此时不建议用多重继承,而是建议使用组合。在如下的CompositionDemo.py代码里,我们将通过组合改善代码的结构。
01 # coding=utf-8 02 class PrintByA3: # 打印的类,在A3纸上打印 03 def print(self): 04 print("Print File in A3.") 05 class PrintByA4: # 在A4纸上打印 06 def print(self): 07 print("Print File in A4.") 08 class PrintHandler(): 09 def __init__(self): 10 self.printByA3 = PrintByA3() 11 self.printByA4 = PrintByA4() 12 def handleFileAsA3(self): 13 self.printByA3.print() 14 def handleFileAsA4(self): 15 self.printByA4.print() 16 handler = PrintHandler() 17 handler.handleFileAsA3() # Print File in A3. 18 handler.handleFileAsA4() # Print File in A4.
在第2行和第5行定义的两个类里,我们同样实现了在A3和A4纸上打印两种功能。但是在第8行的PrintHandler类里,我们不再使用多重继承。
在第9行的__init__构造函数里,我们实例化了两个对象,在PrintHandler类里组合了两种打印的功能类,这样在第12行和第14行的两个方法里就能调用相关方法,实现不同方式的打印功能。从第17行和第18行的语句里,我们能看到组合的效果。
虽然以组合模式开发出的代码量比以多重继承要多,但是代码结构更为清晰,而且在使用的时候不会出现困惑。所以在使用继承特性时,如果出现两个父类具有相同的方法这种情况,就可以改用上述基于组合的实现模式。