7.8 【进阶】类的 Mixin 设计模式

类的单继承,是开发者再熟悉不过的继承方式,写起来也毫不费力。

而多继承呢,见得很多,写得很少。在很多的项目代码里,你还会见到一种很奇怪的类,他们有一个命名上的共同点,就是在类名的结尾,都喜欢用 Mixin。

1. 认识Mixin模式

那我们今天就来讲讲这个 Mixin,对于这个Mixin,如何理解?它其实是一种设计模式,如果开发者之间没有产生这样一种设计模式的共识,那么设计模式将不复存在。

为了让大家,对这个 Mixin 有一个更直观的理解,我摘录了网上一段说明。

继承是一个”is-a”关系。比如轿车类继承交通工具类,因为轿车是一个(“is-a”)交通工具。一个物品不可能是多种不同的东西,因此就不应该存在多重继承。不过有没有这种情况,一个类的确是需要继承多个类呢?

答案是有,我们还是拿交通工具来举例子,民航飞机是一种交通工具,对于土豪们来说直升机也是一种交通工具。对于这两种交通工具,它们都有一个功能是飞行,但是轿车没有。所以,我们不可能将飞行功能写在交通工具这个父类中。但是如果民航飞机和直升机都各自写自己的飞行方法,又违背了代码尽可能重用的原则(如果以后飞行工具越来越多,那会出现许多重复代码)。

怎么办,那就只好让这两种飞机同时继承交通工具以及飞行器两个父类,这样就出现了多重继承。这时又违背了继承必须是”is-a”关系。这个难题该怎么破?

这时候 Mixin 就闪亮登场了。飞行只是飞机做为交通工具的一种(增强)属性,我们可以为这个飞行的功能单独定义一个(增强)类,称之为 Mixin 类。这个类,是做为增强功能,添加到子类中的。为了让其他开发者,一看就知道这是个 Mixin 类,一般都要求开发者遵循规范,在类名末尾加上 Mixin 。

举个例子

class Vehicle(object):
    pass

class PlaneMixin(object):
    def fly(self):
        print('I am flying')

class Airplane(Vehicle, PlaneMixin):
    pass

使用Mixin类实现多重继承要遵循以下几个规范

  • 责任明确:必须表示某一种功能,而不是某个物品;

  • 功能单一:若有多个功能,那就写多个Mixin类;

  • 绝对独立:不能依赖于子类的实现;子类即便没有继承这个Mixin类,也照样可以工作,就是缺少了某个功能。

2. 不使用Mixin的弊端

你肯定会问,不使用 Mixin 行吗?

当然可以,这个问题就像在问,我不遵循 PEP8 代码规范行吗?完全没问题,只是不推荐那样做。

那么到底有什么理由,让我们要去用到 Mixin 设计模式呢?

不使用的话,大概有如下三点弊端:

1、结构复杂

单继承中一个类的父类是什么,父类的父类是什么非常明确。多继承一个类有多个父类,父类又有多个父类,继承关系复杂。

2、优先顺序模糊

多个父类中有同名方法,在开发过程中,容易造成思维混乱,子类不知道继承哪个父类,会增加开发难度。关于子类的继承顺序,有一个比较复杂的 C3 算法,如果你还不清楚,可以点击我的另一篇文章 ,了解一下。

3、功能冲突

多重继承有多个父类,但是子类只能继承一个,对于同名方法,就会导致另一个父类的方法失效。