Mixins

除了传统的面向对象继承方式,mixins是一个强大的概念,它允许我们跨多个类层次结构重用代码,而且这种层次结构支持交叉关系。

这个概念相对比较难以理解,我们来看一个示例。我们这里有一个名为Animal的父类,它有三个子类(Mammal,Bird和Fish)。在底部,我们有具体的一些子类,每个子类具有不同的行为。例如有些动物有共同的行为:猫(Cat)和鸽子(Dove)都可以行走,但是猫不能飞。这些行为与此分类正交,因此我们无法在父类中实现这些行为。

如果一个类可以拥有多个父类,那就很容易办到。我们可以创建另外三个类:Walker,Swimmer,Flyer。在那之后,我们只需让Cat继承Walker,Dove继承Walker和Flyer即可。但在Dart中,每个类(除了Object类)都只能有一个父类。


intro


我们需要一种在多个类层次结构中重用类的代码的方法。Mixins就能够办到这一点!

Dart

// 动物
abstract class Animal {}
// 哺乳动物
abstract class Mammal extends Animal {}
// 鸟类
abstract class Bird extends Animal {}
// 鱼类
abstract class Fish extends Animal {}
// 跑的行为类
abstract class Walker {
  factory Walker._() => null;

  void walk() {
    print('I am walking');
  }
}
// 游的行为类
abstract class Swimmer {
  factory Swimmer._() => null;

  void swim() {
    print('I am swimming');
  }
}
// 飞的行为类
abstract class Flyer {
  factory Flyer._() => null;

  void fly() {
    print('I am 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> args) {
  Cat cat = Cat();
  cat.walk();

  Bat bat = Bat();
  bat.walk();
  bat.fly();
}

TypeScript

// 动物超类
abstract class Animal {}
// 哺乳动物超类
abstract class Mammal extends Animal {}
// 鸟类超类
abstract class Bird extends Animal {}
// 鱼类超类
abstract class Fish extends Animal {}
// 跑的混入类
abstract class  Walker {
  walk(): void {
    console.log('I am walking')
  }
}
// 游的混入类
abstract class  Swimmer {
  swim(): void {
    console.log('I am swimming')
  }
}
// 飞的混入类
abstract class  Flyer {
  fly(): void {
    console.log('I am flying')
  }
}

// 修饰器注入混入
function mixins(mixinObjs: any[]) {
  // TS通过帮助函数实现混入操作
  const applyMixins = (derivedCtor: any, baseCtors: any[]) => 
    baseCtors.forEach(baseCtor => {
      Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
        derivedCtor.prototype[name] = baseCtor.prototype[name]
      })
    })
  return function(target) {
    applyMixins(target, mixinObjs)
  }
}

// 海豚
@mixins([Swimmer])
class Dolphin extends Mammal implements Swimmer {
  swim: () => void
}
// 蝙蝠
@mixins([Walker, Flyer])
class Bat extends Mammal implements Walker, Flyer {
  walk: () => void
  fly: () => void
}
// 猫
@mixins([Walker])
class Cat extends Mammal implements Walker {
  walk: () => void
}
// 鸽子
@mixins([Walker, Flyer])
class Dove extends Bird implements Walker, Flyer {
  walk: () => void
  fly: () => void
}
// 鸭子
@mixins([Walker, Swimmer, Flyer])
class Duck extends Bird implements Walker, Swimmer, Flyer {
  walk: () => void
  swim: () => void
  fly: () => void
}
// 鲨鱼
@mixins([Swimmer])
class Shark extends Fish implements Swimmer {
  swim: () => void
}
// 文鳐鱼
@mixins([Swimmer, Flyer])
class FlyingFish extends Fish implements Swimmer, Flyer {
  swim: () => void
  fly: () => void
}

const cat = new Cat()
cat.walk()

const bat = new Bat()
bat.walk()
bat.fly()
语法

我们明白了Mixins为什么如此有用,下面让我们看看如何创建和使用它们。

Mixins通过普通的类声明隐式定义:

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

如果我们不想让我们创建的Mixins被实例化或者再扩展,我们可以把它定义为:

abstract class Walker {
  factory Walker._() => null;

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

要使用Mixins的话,需要使用with关键字,后跟一个或多个Mixin的名称:

class Cat extends Mammal with Walker {}

class Bat extends Mammal with Walker, Flyer {}

我们在Cat类上定义了Walker mixin,它允许我们调用walk()方法而不是fly()方法;但我们的Bat类却既可以调用walk()方法也可以调用fly()方法。虽然他们都是继承Mammal父类,但是我们并不能在Mammal父类去实现这2个方法,因为它们并不存在共性。

main(List<String> args) {
  Cat cat = Cat();
  cat.walk();
  // cat.fly();  // NoSuchMethod

  Bat bat = Bat();
  bat.walk();
  bat.fly();
}
趋势

Mixins在Dart中发展的非常快,以致于我们可以通过继承的方式来约束Mixins,看下面这段代码的实现:

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

class MySuper implements Super {
  @override
  void method() {
    print('MySuper');
  }
}

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

class Client extends MySuper with Mixin {

}

main(List<String> args) {
  Client().method();
}

输出:

MySuper
Sub

从上面可以看出,我们可以使用mixin关键字来定义个mixin object,同时通过on关键字来继承一个Super超类,此时该mixin就已经被Super超类所约束。这意味着之后在使用mixin时,混入mixin的类必须继承或实现Super,因为mixin中使用了Super.提供的功能。

results matching ""

    No results matching ""