关于Flutter中的mixins

108 阅读3分钟

前言

mixins一直是我一个比较困惑的关键字,虽然已经做了flutter几个月了,但是并没有去搞懂mixins是什么功能,最佳刚好看了些文章,这里做个终结。

为什么需要mixins

image.png

这里我们有一个Animal的超类,它有三个子类型Mammal, Bird和Fish, 最底下我们有具体的类,类左边的小方块代表一些行为,例如,蓝色的小方块代表swim行为.

一些动物有相同的行为,例如cat和dove都可以walk, 但是cat不能飞。

这些行为分布不均匀,不能在超类里面实现。当然你可以想到的是我再抽象一些Walker,Swimmer,Flyer这些类,但是在Dart中只能支持单继承.

既然不能使用继承,那我只好每个类都写一遍它的实现咯?不过Dart提供了更方便的方式就是使用mixins

对于mixins的定义是:

mixins是重用一块类代码在多个类层级中

如何使用mixins

首先我们创建一个mixins, 它和创建普通类的方式一样

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

为了防止mixin被初始化或者继承,我们可以定义为abstract class

abstract class Walker {
  // This class is intended to be used as a mixin, and should not be
  // extended directly.
  factory Walker._() => null;

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

去使用mixin,使用with关键字,后面跟上mixin名字

class Cat extends Mammal with Walker {}

class Dove extends Bird with Walker, Flyer {}

定义Walker mixin在Cat类上,这得Cat可以调用walk()方法。

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

  // 一只cat可以walk.
  cat.walk();

  // 一只dove可以walk和fly.
  dove.walk();
  dove.fly();

  // 一只cat不可以调用fly.
  // cat.fly();
}

mixins的继承关系

猜猜下面的代码是什么输出

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);
}

AB和BA类都继承来自P,但是mixin A和B的顺序不同, 3个类A,B, P都有一个getMessage方法。

首先我们调用AB实例化对象的的getMessage,然后调用BA类实例化对象的的getMessage。所以最终的结果是什么呢?

最终它会输出BA.

要了解为什么,我们需要搞懂mixins的继承顺序. 它是线性化的,它的继承关系如下

image.png

所以它是一种线性的继承顺序,从左到右。

mixins的类型

首先我们来看看下面程序的输出

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() {
  AB ab = AB();
  print(ab is P);
  print(ab is A);
  print(ab is B);

  BA ba = BA();
  print(ba is P);
  print(ba is A);
  print(ba is B);
}

所有的print都会打印true。这意味着,由mixin声明的类,不光是超类的子类,也是mixin的子类.

关键字on

另外dart还提供一个on关键字用于限制mixin的使用范围。

例如:

abstract class Super {
  void method() {
    print("Super");
  }
}

class MySuper implements Super {
  void method() {
    print("MySuper");
  }
}

mixin Mixin on Super {
  void method() {
    super.method();
    print("Sub");
  }
}

class Client extends MySuper with Mixin {}

void main() {
  Client().method();
}

在示例代码中Mixin的使用实际限制在必须继承Super的类,因为Mixin用on关键字限制了它的作用域是Super的子类.

什么时候使用mixins?

当需要实现某个共享功能在类里,但是不想破坏原有的类层级结构的时候可以使用mixins进行类的抽象。就拿之前Animal案例来说,walk实际上是一个可以在各个类中共享的功能,但是我不想在超类里去实现,这样会破坏类层级结构,就可以使用mixins这种方式了.