Dart 语言中extends、implements、mixin的区别

Chris Scoot
6 min readMay 3, 2024

三种本质上都是为了代码复用,单继承语言下如何

1、extends 单继承,与所有面向对象语言一样,子类可以继承父类的所有属性、方法,且可以重写覆盖父类的方法

abstract class A {
void test(); ///子类必须重写
void test22() {///子类可不重写
print("test22===");
}
}

class B extends A {
@override
void test() {///父类是虚类,且此函数父类无默认实现,子类必须实现
super.test22();///调用父类的实现
}
}

2、implements 接口实现

1、与继承不同,非父子关系,无法调用或者重写覆盖父类方法

2、必须实现接口中的所有方法(哪怕接口中已经有默认实现)

abstract class A {
void test();
void test22() {
print("test22===");
}
}

class B implements A {///子类必须实现接口的所有方法,且无法调用接口中的默认实现
@override
void test() {
super.test();///Error 无法调用
}

@override
void test22() {
super.test22()///Error 无法调用
}
}

class C extends B implements A{///OK,B已经实现了A
}

3、mixin 混入

在不继承该类的情况下,混入该类使得自己可以拥有该类的所有方法。其本质是:虽然代码中没有显示继承该类,但是编译器会将该类插入到当前类的继承链中,使得自己可以使用mixin类的方法。因而mixin类中的方法如果调用了super,会按照最后生成的继承链往上调用。

abstract class A {
void test();
void testAA() {
print("testAA===");
}
}

abstract class B {
void test();
void testBB() {
print("testBB===");
}
}

///M1未来可能的父类必须是A且B,由于单继承只能继承一个父类,可以是extends、implements、mixin三者任意组合
///所以在M1中可以事先调用A或者B中的方法
mixin M1 on A, B {///要想混入M1,条件是该类必须同时继承或者实现了(A、B)
void test33() {
test();///调用父类的test方法,可能是A中的,也有可能是B中的。看具体实现
}

@override
void testBB() {///重写B中的方法
print("M1");
super.testBB();
}
}

class T extends B implements A {///此处A、B的顺序调换,T的子类依然可以with M1,因为都满足了on M1的条件
@override
void test() {}///上面test33中调用的方法会到此处

@override
void testAA() {}
}

class TT extends T with M1 {}///OK,因为on M1的条件已经被父类T满足

///允许重复with相同的类,类层次结构会多加一层
///类层次结构相当于:从上往下,父类->子类
/// T :grandparent
/// M1 :parent
/// M1 :son
/// TTT :grandson
class TTT extends T with M1,M1 {}///OK

又参考如下代码:

mixin A {
void test() {
print("test===A");
}

void testAA() {
print("testAA===A");
}
}

mixin B on A {
void test() {
super.test();
print("test===B");
}

void testBB() {
print("testBB===B");
}
}

mixin M1 on A, B {///on后面的顺序不重要
void test33() {
print("test33==M1");
test();
}

@override
void testBB() {
print("testBB M1");
super.testBB();
}
}

///继承关系:A <- B <- M1 <- T
//所以,每次找方法时,都会从继承链的最底端T,往上找
class T with A, B, M1 {///with后面的顺序至关重要,关系到继承关系的顺序
@override
void test33() {
print("test33 T");
super.test33();
}

@override
void test() {
print("test T");
super.test();
}
}

void main() {
final aaa = T();
aaa.test(); ///调用顺序T::test -> M1::test不存在 -> B::test -> A::test
aaa.test33();///调用顺序T::test33 ->M1::test33 ->调用aaa.test,按上一步走
aaa.testAA();///调用顺序T::testAA不存在 -> M1::testAA不存在 -> B::testAA不存在 -> A::testAA
aaa.testBB();///调用顺序T::testBB不存在 -> M1::testBB -> B::testBB
}

最后输出如下:
flutter: test T
flutter: test===A
flutter: test===B
flutter: test33 T
flutter: test33==M1
flutter: test T
flutter: test===A
flutter: test===B
flutter: testAA===A
flutter: testBB M1
flutter: testBB===B

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Chris Scoot
Chris Scoot

Written by Chris Scoot

擅长C语言、C++、iOS开发(Objective-C\Swift)、Flutter开发(Dart语言)、GO语言、Python等,拥抱新技术,热爱AI领域,对OpenCV、Pytorch\Tensorflow充满热情。

No responses yet