Mixins 是什么
Mixin 是一种代码复用方式,可以在互不相关的类继承体系中复用代码,目标是批量为类提供成员实现。有点类似多继承,但是它的目的是给一个类增加一些各种的模块功能。
使用 Mixin
通过关键字 with,后跟一个或多个 Mixin 名称。
class Musician extends Performer with Musical {
// 代码
}
class Maestro extends Person with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
Code language: Dart (dart)
定义 Mixin
使用 mixin 关键字声明。
补充:
mixin class(Dart 3.0+)可以同时当作普通类、Mixin 使用。
强制约束
mixin/mixin class不能写extends- 不能声明任何生成构造函数(generative constructor)
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}
class Musician with Musical {}
void main() {
var m = Musician();
m.canConduct = true;
m.entertainMe(); // Waving hands
}
Code language: Dart (dart)
执行结果
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Musician is playing
Musician is playingCode language: CSS (css)
Mixin 需要调用外部成员
Mixin 自身无法定义的方法 / 属性
Mixin 经常需要调用一些自己没有实现的成员,下面提供 4 种标准方案。
在 Mixin 内部定义抽象成员
Mixin 声明抽象方法,所有使用该 Mixin 的类必须实现这个抽象方法。
mixin Musician {
// 抽象方法,使用者必须实现
void playInstrument(String instrumentName);
void playPiano() {
playInstrument('Piano');
}
void playFlute() {
playInstrument('Flute');
}
}
//使用者必须重写实现
class Virtuoso with Musician {
@override
void playInstrument(String instrumentName) {
print('Plays the $instrumentName beautifully');
}
}
void main() {
var artist = Virtuoso();
artist.playPiano();
artist.playFlute();
}
Code language: Dart (dart)
Plays the Piano beautifully
Plays the Flute beautifully
通过抽象 Getter 访问宿主类的状态
Mixin 定义抽象 getter,以此读取宿主类的字段,实现跨类状态访问。
/// 可以混入任意带有 name 属性的类,自动提供基于 name 的 == 和 hashCode
mixin NameIdentity {
String get name;
@override
int get hashCode => name.hashCode;
@override
bool operator ==(Object other) =>
other is NameIdentity && name == other.name;
}
class Person with NameIdentity {
final String name;
Person(this.name);
}
void main() {
var p1 = Person("Alice");
var p2 = Person("Alice");
var p3 = Person("Bob");
print(p1 == p2); // true
print(p1 == p3); // false
}
Code language: JavaScript (javascript)
Mixin 实现接口 implements
Mixin 使用 implements 约束接口,强制混入类补齐接口全部方法。
abstract interface class Tuner {
void tuneInstrument();
}
mixin Guitarist implements Tuner {
void playSong() {
tuneInstrument();
print('Strums guitar majestically.');
}
}
class PunkRocker with Guitarist {
@override
void tuneInstrument() {
print("Don't bother, being out of tune is punk rock.");
}
}
void main() {
PunkRocker().playSong();
}
Code language: JavaScript (javascript)
Don't bother, being out of tune is punk rock.
Strums guitar majestically.
on 子句:限定 Mixin 只能被特定父类的子类使用
on 作用:限制只有继承自指定类型的类,才能混入当前 Mixin。
同时 Mixin 内部可以调用父类的成员、执行 super.xxx()。
仅当你需要在 Mixin 内部使用
super调用父类方法时,才使用on!
class Musician {
void musicianMethod() {
print('Playing music!');
}
}
// 仅能混入 Musician 的子类
mixin MusicalPerformer on Musician {
void performerMethod() {
print('Performing music!');
super.musicianMethod(); // 可以调用被on约束的父类方法
}
}
// SingerDancer 继承 Musician,因此可以混入 MusicalPerformer
class SingerDancer extends Musician with MusicalPerformer {}
void main() {
SingerDancer().performerMethod();
}
Code language: Dart (dart)
Performing music!
Playing music!
SingerDancer 混入了MusicalPerformer 所以 可以使用它里面的 performerMethod方法
混入就类似这样,一个类可以把另外一个mixin 里面的方法拿过来,这样自己就可以用了。
⚠️ 错误示范:
如果一个类没有继承
Musician,直接with MusicalPerformer会编译报错。
class /mixin/mixin class 区别
mixin:只能通过with使用,不能用extends继承class:可以extends,不能直接当作 mixin 使用mixin class:- 既可以用
with当作 Mixin - 也可以用
extends当作普通父类
- 既可以用
约束同样生效:
- mixin / mixin class 不能写 extends、with
- class / mixin class 不能写 on
mixin class Musician {
void play() {
print("Musician is playing");
}
}
// 作为 Mixin 使用
class Novice1 with Musician {}
// 作为普通父类继承
class Novice2 extends Musician {}
void main() {
Novice1().play();
Novice2().play();
}
Code language: Dart (dart)
运行结果
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Musician is playing
Musician is playing
Code language: CSS (css)