Flutter中的abstract、implements、extends、mixin关键字

1、abstract

使用关键字 abstract 标识一个类可以让类成为抽象类,抽象类将无法被实例化,也就是说不能直接使用抽象类,只能使用抽象类的子类。
抽象类定义的方法只定义不进行实现,就是抽象方法(还有抽象属性),需要子类进行方法实现,已经实现的方法就是普通方法。

abstract class Animal{
  void updateChildren();
}
class Dog extends Animal{
  @override
  void updateChildren() {
    // 已经实现的方法子类不强制实现(普通方法),只有定义没有实现的是抽象方法子类必须实现
  }
}
// Animal a = Animal();//报错,抽象类没办法直接实例化一个方法(抽象类不能直接使用,要使用抽象类的子类)
2、implements

一个类可以通过关键字 implements 来实现一个或多个接口并实现每个接口定义的 API,例如想要创建一个 A 类支持调用 B 类的 API 且不想继承 B 类,则可以实现 B 类的接口。

class Person {
  final String _name;

  Person(this._name);

  String greet(String who) => 'Hello, $who. I am $_name.';
}

class Impostor implements Person {
  String get _name => '';

  String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));
}

如果需要实现多个类接口,可以使用逗号分割每个接口类

class Point implements Comparable, Location {...}
3、extends

使用 extends 关键字来创建一个继承自某个类的子类,并可使用 super 关键字引用一个父类。

class Television {
  void turnOn() {
  }
}

class SmartTelevision extends Television {
  @override
  void turnOn() {
    super.turnOn();
  }
}

如果要复用抽象类里面的方法,并且要用抽象方法约束子类的话就用extends继承抽象类。
如果只是把抽象类当作标准的话就用implement实现抽象类。

需要注意implementsabstract 需要实现接口方法,但是extends 如果具备同名方法就无需重写。看下面的例子:

abstract class First {
  void doPrint() {
    print('First');
  }
}
 
abstract class Second {
  void doPrint() {
    print('Second');
  }
}
 
class Father {
  void doPrint() {
    print('Father');
  }
}
 
class Son extends Father implements First,Second {}

调用:

Son().doPrint();

打印:

Father

因为已经在父类已经实现了同名方法,所以不需要再子类重新实现doPrint()方法。这时如果在Second或者First中再加入其他方法,结果我们可以想到,肯定会报错。

4、mixin和with

mixin 是Dart 2.1 加入的特性,以前版本通常使用abstract class代替。Dart为了支持多重继承,引入了mixin关键字,它的特点是:
1.mixin定义的类不能有构造方法,这样可以避免继承多个类而产生的父类构造方法冲突。
2.可以混入多个类。
3.with关键字能够实现mixin,可以想象成多继承,而且是以类似于栈的形式实现(最后一个混入的 mixins 会覆盖前面一个 mixins 的特性,这里需要注意)。
4.withimplements的区别就是with不需要实现继承接口方法。

想要实现一个 Mixin,请创建一个继承自 Object且未声明构造函数的类。除非你想让该类与普通的类一样可以被正常地使用,否则请使用关键字 mixin 替代 class

mixin Musical {    }   //使用 mixin 关键字创建一个混入类

可以使用关键字 on 来指定哪些类可以使用该 Mixin 类。比如有 MixinMusicalPerformer,但是 MusicalPerformer只能被 Musician 类使用,则可以这样定义 MusicalPerformer

class Musician {}
//使用 on 关键字规定混入类 MusicalPerformer 只能在子类继承自Musician 的时候才能使用。
//
mixin MusicalPerformer on Musician {}
class SingerDancer extends Musician with MusicalPerformer {}

on关键字会把使用了混入类的自动关联为父子关系,看下面的例子:

class Father {
  void init() {
    print('Father init');
  }
}
//当使用on关键字,则表示该mixin只能在那个类的子类使用了,
// 那么结果显然的,mixin中可以调用那个类定义的方法、属性
mixin FirstMixin on Father {
  void init() {
    print('FirstMixin init start');
    super.init();
    print('FirstMixin init end');
  }
}
 
mixin SecondMixin on Father {
  void init() {
    print('SecondMixin init start');
    super.init();
    print('SecondMixin init end');
  }
}
 
class Son2 extends Father with FirstMixin, SecondMixin {
  @override
  void init() {
    print('Son2 init start');
    super.init();
    print('Son2 init end');
  }
}

方法调用及打印:

Son2().init();

flutter: Son2 init start
flutter: SecondMixin init start
flutter: FirstMixin init start
flutter: Father init
flutter: FirstMixin init end
flutter: SecondMixin init end
flutter: Son2 init end

这里super调用会发现,with关键字把FirstMixin和SecondMixin以及Father自动关联为父子,这一切都是基于on关键字,且对Father这个家族(可以理解为整个家族)增加束缚,Son2这个类也只能继承Father,如果增加其他家族的mixin,就会报错。

class OtherFamily{
  void init(){
    print('其他家族');
  }
}
 
mixin OtherFamilyMixin on OtherFamily{
@override
  void init() {
    // TODO: implement init
    super.init();
  }
}
 
class Son2 extends Father with FirstMixin, SecondMixin ,OtherFamily{
   //这里如果 with 最后面跟的是 OtherFamilyMixin,那么肯定就会报错,
  //原因上面已经说过了,继承自Father类,只能使用FirstMixin和SecondMixin两个混入类。
  @override
  void init() {
    print('Son2 init start');
    super.init();
    print('Son2 init end');
  }
}

打印:

flutter: Son2 init start
flutter: 其他家族
flutter: Son2 init end

这里发生了有点混乱的情况,super直接指向OtherFamily,但是他又不忘记继承的Father,还是依旧能调用Father里的方法。

on关键字后边不止可以跟一个类,其实可以跟多个类,但是跟了多个类,则在使用混入类的时候,需要在with关键字的后面先跟上除继承类的其他类,否则如果先跟的是混入类就会报错

//新建一个类
class Mother{
  void initMother() {}
}
//将原来的混入类由原来的Father改为Father,Mother
mixin SecondMixin on Father,Mother {
  void init() {
    print('SecondMixin init start');
    super.init();
    print('SecondMixin init end');
  }
}

class Son2 extends Father with FirstMixin,Mother,SecondMixin {
  //这里再进行混入的时候,需要先写FirstMixin或Mother,将SecondMixin写在最后,否则会报错
  @override
  void init() {
    print('Son2 init start');
    super.init();
    print('Son2 init end');
  }
}

还可以像下面这样使用

class A { void a(){ print("a"); } }
class A1 { void a(){ print("a1"); } }
class B with A,A1{ }
class B1 with A1,A{ }
class B2 with A,A1{ void a(){ print("b2"); } }
class C { void a(){ print("c"); } }
class B3 extends C with A,A1{ }
class B4 extends C with A1,A{ }
class B5 extends C with A,A1{ void a(){ print("b5"); } }

B b = B();      b.a();    //a1
B1 b1 = B1();   b1.a();   //a
B2 b2 = B2();   b2.a();   //b2
B3 b3 = B3();   b3.a();   //a1
B4 b4 = B4();   b4.a();   //a
B5 b5 = B5();   b5.a();   //b5

这里可以对某一个类进行拆解进行分析

class B3 extends C with A,A1{}
//B3类的结构可以分解为
class CA = C with A;
class CAA1 = CA with A1;
class B3 extends CAA1{ }

如果新建一个类,将上面讲的关键字都合在一起

class D extends C with A implements A1{ }
//创建对象,调用方法
D().a(); //a

这里说明一下,A1是接口,with关键字依旧遵守上边将的性质,首先实现A中的方法(with 相当于实现了可以省略不写,但是同名,也相当于重写了implements的接口),如果把A中的a()方法注释掉,则会打印c

看下面这个例子

mixin _CounterStateMixin < T extends StatefulWidget> on State<T> {
  int _counter = 0;
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
}
class _MyHomePageState extends State<MyHomePage> with _CounterStateMixin {

  @override
  void initState() {
    _incrementCounter();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容