最近在学习flutter,研究别人的组件,刚好看到一段代码设计,如下(精简过后):
代码解释:
1、抽象类ColumnType
提供了属性defaultValue
、方法test()
;
2、具体类ColumnTypeNumber
实现implements
了ColumnType
;
3、具体类ColumnTypeNumber
混入with
了ColumnTypeWithNumber
;
4、因为2,所以需要覆盖1中提供的成员defaultValue
、test()
,但是又因为3(定义了方法test()
),所以该类不需要覆盖test()
,但是又不需要写override
,但是 mixin ColumnTypeWithNumber
里面又不能覆盖抽象类的属性defaultValue
;
5、反而mixin ColumnTypeWithNumber
定义的属性format
,却成了具体类ColumnTypeNumber
需要覆盖的成员;
abstract interface class ColumnType {
/// 定义一个属性
dynamic get defaultValue;
/// 定义一个抽象方法
void test();
}
class ColumnTypeNumber with ColumnTypeWithNumber implements ColumnType {
@override
final dynamic defaultValue;
@override
final String format;
/// 构造函数
const ColumnTypeNumber({this.defaultValue, this.format = ''});
}
mixin ColumnTypeWithNumber {
String get format;
void test() {}
}
如果没有ColumnTypeWithNumber
,那么ColumnTypeNumber
实现抽象类后,代码如下:
abstract interface class ColumnType {
/// 定义一个属性
dynamic get defaultValue;
/// 定义一个抽象方法
void test();
}
class ColumnTypeNumber implements ColumnType {
@override
final dynamic defaultValue;
@override
void test() {}
/// 构造函数
const ColumnTypeNumber({this.defaultValue});
}
直接 override
属性 defaultValue
方法 test()
即可;但是加入with
后(成了上面第一段代码),疑问就来了,mixin
可以理解是一种提供共享代码的方式。
具体类ColumnTypeNumber
with
了ColumnTypeWithNumber
,也implements
了ColumnType
疑问点:
1、因为ColumnTypeNumber with ColumnTypeWithNumber
,所以表示拥有了test()
,但是却可以不用@override
标记;
2、因为ColumnTypeNumber with ColumnTypeWithNumber
,但是却不得不@override
里面的属性format
,这看上去又像是“实现了”接口一般(所以需要override里面的成员)。
3、mixin ColumnTypeWithNumber
里面的方法能够当值覆盖抽象类的方法,但是里面却不能够覆盖抽象类的属性defaultValue
;
4、源码比这个复杂,会实现多个接口,with多个mixin代码块,所以导致具体类里面的属性、方法搞不清来自哪里?
5、源码里面很多奇怪的写法,例如上面提到的abstract interface class
三个关键词修饰。感觉“灵活”但是“凌乱”。
该怎么来记忆(理解)这一块拧巴的逻辑呢?
结论:想来想去,最简单的办法是把with
可以理解为“继承”,如果定义了抽象成员,如String get format;
(没有实现),那么就需要override
,如果是具体实现的成员,如test()
,那就可以理解为被继承的成员,如果方法名和其他抽象接口同名,刚好可以当作覆盖作用(可以不写override)。
大概明白你混乱的原因了,主要来自于有的写了
@override
有的有没写。其实你想复杂了,Dart 里的
@override
本来就是可以省略的,写和不写对于执行结果没有任何区别 —— 只要你在子类里(不管它是继承的还是混入的)重新定义父类的属性或方法,那它就是重写。@override
的唯一用途就是给人看的,让你知道这个东西是重写过的;你要说对编译结果有影响的话倒是也有,那就是如果你这个属性或方法在父类里并不存在,你强行声明它是“复写”,编译器会报错。但还是前面那句话,对执行结果没有任何影响。显然你贴的这段代码的开发者没有遵守完全一致的编码风格,导致有的写了注解、有的没写,所以你才混乱。