OCP原则: 多用继承,少修改
多态:在面向对象中,父类、子类
多继承的弊端
C++支持多继承,Java舍弃了多继承
多继承带来的路径选择问题,究竟继承哪个父类的特征呢?
MRO(method resolution order)
多继承的缺点
当类很多,继承复杂的情况下,继承的路径太多,很难说清什么样的继承路径;
python语法是允许多继承,但python代码是解释执行,只有执行的时候,才发现错误;
class Document: # 抽象基类
"""抽象基类中可以定义多个抽象方法,可以全都不实现,只是约束子类的规范,子类中进行覆盖"""
def __init__(self, content):
self.content = content
def print(self): # 抽象方法 ——> 抛出异常的方法(只定义不实现的方法)
# 在python中如果采用这种方式定义的抽象方法,子类可以不实现,直到子类使用该方法时才报错
raise NotADirectoryError('不用实现')
def printable(cls): # 用装饰器增强一个类,把功能给类附加上去,哪个类需要它,就装饰它
def _reg(self):
print(self.content, '{}'.format(self.__class__.__name__)) # format里面的self不能少,否则会出错
cls.print = _reg
return cls # 利用装饰器给类动态增加方法
def fn(name: str): # 利用装饰器给类动态增加变量
def wrapper(cls):
cls.NAME = name
return cls
return wrapper
@printable
class Word(Document): # 先继承后装饰
pass
# def print(self): # 覆盖父类的方法
# print(self.content, '~~~ in word')
@fn('xyz')
class Pdf(Document):
def print(self):
print(self.content, '~~~ in pdf')
w = Word('test word string')
w.print()
p = Pdf('test pdf string')
p.print()
print(p.NAME)
Mixin
class Document:
def __init__(self, content):
self.content = content
class Word(Document):
pass
class Pdf(Document):
pass
class PrintableMixin:
def print(self):
print(self.content, '{}'.format(self.__class__.__name__))
class PrintableWord(PrintableMixin, Word): # Mixin类写在最前面
pass
def printable(cls): # 用装饰器增强一个类,把功能给类附加上去,哪个类需要它,就装饰它
def _reg(self):
print(self.content, '{}'.format(self.__class__.__name__)) # format里面的self不能少,否则会出错
cls.print = _reg
return cls # 利用装饰器给类动态增加方法
@printable
class PrintablePdf(Word):
pass
class SuperPrintableMixin(PrintableMixin):
def print(self):
print('~~' * 20)
super().print()
print('~~' * 20)
class SuperPrintablePdf(SuperPrintableMixin, Pdf):
pass
print(SuperPrintablePdf.__dict__)
print(SuperPrintablePdf.mro())
# [<class '__main__.SuperPrintablePdf'>, <class '__main__.SuperPrintableMixin'>, <class '__main__.PrintableMixin'>,
# <class '__main__.Pdf'>, <class '__main__.Document'>, <class 'object'>]
spp = SuperPrintablePdf('super print pdf')
spp.print()
pw = PrintableWord('test pw string')
print(PrintablePdf.__dict__) # 装饰器会增加类的print方法。在其字典中可以看到
# {'__module__': '__main__', '__doc__': None, 'print': <function printable.<locals>._reg at 0x0000000002840048>}
print(PrintablePdf.mro())
# [<class '__main__.PrintablePdf'>, <class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>]
print(pw.__class__.__dict__)
# {'__module__': '__main__', '__doc__': None}
print(pw.__class__.mro()) # 结果为列表
# [<class '__main__.PrintableWord'>, <class '__main__.PrintableMixin'>,
# <class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>]
pw.print() # test pw string PrintableWord
Mixin类
Mixin本质上就是多继承实现的;
Mixin体现的是一种组合的设计模式;
在面向对象的设计中,一个复杂色类,往往需要很多功能,而这些功能又来自不同的类提供,这就需要很多的类组合在一起 。
从设计模式的角度来说,多组合,少继承。
Mixin类的使用原则
- Mixin类中不应该显示的出现__init__初始化方法
- Mixin类通常不能独立工作,因为它是准备混入别的类中的部分功能实现
- Mixin类的祖先类也应是Mixin类
使用时,Mixin类通常在继承列表的第一个位置,例如class SuperPrintablePdf(SuperPrintableMixin, Pdf):pass