略显混乱的dart继承、接口、with等,该怎么理解?

最近在学习flutter,研究别人的组件,刚好看到一段代码设计,如下(精简过后):

代码解释:
1、抽象类ColumnType提供了属性defaultValue、方法test()
2、具体类ColumnTypeNumber 实现implementsColumnType
3、具体类ColumnTypeNumber 混入withColumnTypeWithNumber
4、因为2,所以需要覆盖1中提供的成员defaultValuetest(),但是又因为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 withColumnTypeWithNumber,也implementsColumnType

疑问点:
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)。

阅读 350
1 个回答

大概明白你混乱的原因了,主要来自于有的写了 @override 有的有没写。

其实你想复杂了,Dart 里的 @override 本来就是可以省略的,写和不写对于执行结果没有任何区别 —— 只要你在子类里(不管它是继承的还是混入的)重新定义父类的属性或方法,那它就是重写。

@override 的唯一用途就是给人看的,让你知道这个东西是重写过的;你要说对编译结果有影响的话倒是也有,那就是如果你这个属性或方法在父类里并不存在,你强行声明它是“复写”,编译器会报错。但还是前面那句话,对执行结果没有任何影响

显然你贴的这段代码的开发者没有遵守完全一致的编码风格,导致有的写了注解、有的没写,所以你才混乱。

推荐问题