Mixin是面向对象程序设计语言中的类,提供了方法的实现。其它类可以访问mixin类的方法而不必成为其子类。Mixin有时被称作"included(包含)"而不是"inherited(继承)"。mixin为使用它的class提供额外的功能,但自身却不单独使用(不能单独生成实例对象,属于抽象类)。因为有以上限制,Mixin类通常作为功能模块使用,在需要该功能时“混入”,而且不会使类的关系变得复杂

Mixin有利于代码复用,又避免了多继承的复杂。使用Mixin享有单一继承的单纯性和多重继承的共有性。接口与mixin相同的地方是都可以多继承,不同的地方在于 mixin 是带实现的。Mixin也可以看作是带实现的interface。这种设计模式实现了依赖反转的原则

如果你没有类的基础,请先阅读我们的Dart中的类,理解Dart的继承,接口,再看本文章

可能你会觉得上面说的太复杂,下面以一个真实的示例,看看Mixin在什么时候使用,以及加入了Mixin的类中的代码优先执行顺序,我们来看看下面的类继承图


我们有一个超类Animal,它有三个子类(Mammal, Bird, 和 Fish),三个子类下还有多个子类,这多个子类旁边的小方块代表其行为,比如蓝色小方块表示一个类的实例行为是游泳,灰色表示飞行,黄色表示行走

某些动物可能会共享某一些行为,比如Bat,Dove,Duck,Flying Fish都是会飞行的。但是这些行为与此分类正交,因此我们无法在父类中实现这些行为。

如果一个类可以有多个父类,这将会变得非常简单,我们只需要让第三层动物Cat,Bat等继承多个类的行为,就可以实现。但是Dart只允许继承一个父类

如何在不是在继承基础上在Bat,Cat等类中实现行走,飞行等行为。我们可以找到第二个方案就是将这些行为的类都作为接口来实现,但是这样还差一步没有实现我们的目标,这还会导致很多重复代码,因为你需要在Cat,Bat等类中实现这些动物的行为,比如行走,每个Cat,Bat类都实现一次

我们需要一种在多个类层次结构中重用类的代码的方法,,就是mixin

Mixins are a way of reusing a class’s code in multiple class hierarchies.

这看起来很容易😁,首先我们看看Dart如何定义mixin,下面是一个简单定义的mixin

mixin Musical {
  bool canPlayPiano = false;

  void entertainMe() {
    // code
  }
}

要使用mixin,请使用with关键字后跟一个或多个mixin名称。以下示例显示了两个使用mixins的类

class Musician extends Performer with Musical,Demented {
  // ···
}

现在我们知道基本的语法,下面我们以代码的方式实现上面的案例,首先将行走,飞行等行为定义为mixin,其它的行为都是用以下的方式来定义

mixin Walker {
  void walk() {
    print("I'm walking");
  }
}

注意mixin是不能被实例化的,也不能被继承,如果你要实例化请使用正常的类

下面是这个示例的完整代码


abstract class Animal {}

abstract class Mammal extends Animal {}

abstract class Bird extends Animal {}

abstract class Fish extends Animal {}

mixin Walker {
  void walk() {
    print("I'm walking");
  }
}

mixin Swimmer {
  void swim() {
    print("I'm swimming");
  }
}

mixin Flyer {
  void fly() {
    print("I'm flying");
  }
}

class Dolphin extends Mammal with Swimmer {}

class Bat extends Mammal with Walker, Flyer {}

class Cat extends Mammal with Walker {}

class Dove extends Bird with Walker, Flyer {}

class Duck extends Bird with Walker, Swimmer, Flyer {}

class Shark extends Fish with Swimmer {}

class FlyingFish extends Fish with Swimmer, Flyer {}

main(List<String> arguments) {
  Cat cat = Cat();
  Dove dove = Dove();

  // cat可以行走.
  cat.walk();

  // dove可以飞行.
  dove.walk();
  dove.fly();

  // cat不能飞行.
  // cat.fly();
}

现在你可以会过头来理解顶部描述,如果你能看明白顶部说明你基本理解了Mixin,下面我们继续深入理解Mixin

为了加深理解对理解,我还需要知道使用多个Mixin时那个方法会先被执行,参考以下代码,大家可以留言猜测result的结果是什么

class A {
  String getMessage() => 'A';
}

class B {
  String getMessage() => 'B';
}

class P {
  String getMessage() => 'P';
}

class AB extends P with A, B {}

class BA extends P with B, A {}

void main() {
  String result = '';

  AB ab = AB();
  result += ab.getMessage();

  BA ba = BA();
  result += ba.getMessage();

  print(result);
}

Mixin如此强大,并且规范不断在变化,以后继续更新详细Mixin执行过程