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