Flutter 知識梳理 (Dart) - implements, extends, mixin 的理解

1、前言

在使用Java語言設計類之間關係的時候,咱們會接觸到 組成單元關係鏈接 這兩類概念:html

  • 組成單元:普通類、abstract抽象類,interface接口。
  • 關係鏈接:implements實現,extends繼承。

而在Dart當中,對於這兩類概念進行了增減:函數

  • 組成單元:普通類,abstract抽象類、mixin
  • 關係鏈接:implements實現、extends繼承、with混入。

最大的不一樣有兩點:post

  • 去掉了interface
  • 增長了混入的概念。

下面咱們就來看一下其中涉及到的知識點,前面兩節對比一下JavaDart的區別,最後着重介紹混入的概念。學習

推薦給你們一個網站:dartpad.dartlang.org/ 能夠在線運行。網站

2、組成單元

2.1 普通類

JavaDart的普通類有區別,可是不影響咱們設計類之間的關係,所以再也不贅述。ui

2.2 abstract 抽象類

JavaDart的抽象類定義時大致是同樣的,咱們能夠在其中定義變量、普通方法、抽象方法,它和普通類最大的區別就是 抽象類不能實例化spa

JavaDart在使用抽象類時有一點不一樣:Dart在定義抽象方法時,不須要用abstract修飾設計

abstract class DartAbs {
  
  void absMethod();
  
}
複製代碼

2.3 interface 接口

Dart中,沒有 interface 關鍵字code

順帶咱們複習一下Javaabstractinterface的一些要點:htm

  • 抽象類和接口都不能被實例化。
  • 抽象類要被子類繼承,接口要被類實現。
  • 接口只能作方法的聲明,抽象類能夠作方法的聲明,也能夠作方法的實現。
  • 接口裏定義的變量只能是公共的靜態常量,抽象類中的變量能夠是普通變量。
  • 抽象類裏的抽象方法必須所有被子類實現;接口的接口方法必須所有被子類實現,不然只能爲抽象類。
  • 抽象類裏能夠沒有抽象方法。
  • 若是一個類裏有抽象方法,那麼這個類只能是抽象類。
  • 抽象方法要被實現,因此不能是靜態的,也不能是私有的。
  • 接口可繼承接口,並可多繼承接口,但類只能單繼承。

3、關係鏈接

3.1 extends

JavaDartextends是一致的,只能夠單繼承,要注意的點是:

  • 子類能夠繼承父類裏面 可見的屬性和方法
    • 對於Java來講,可見指的是非private修飾,
    • Dart來講,指的是非下劃線_開頭。
  • 子類調用父類的方法,使用super關鍵字。
  • 子類不會 繼承 父類的構造函數。
class Extends {
  
  void base() {
    print('base');
  }
  
  void log() {
    print('extends');
  }
  
}

class Log extends Extends {
  
  log() {
    print('log');
  }
  
}

void main() {
  Log().base();
  Log().log();
}
複製代碼

輸出結果:

base
log
複製代碼

3.2 implements

implementsextends最大的不一樣就是容許後面接上多個普通或者抽象類,當咱們使用B implement A修飾時,那麼A中的全部的屬性和方法都要在A中實現,不管它原來是抽象方法仍是普通方法

也就是說若是咱們只想要A中的接口定義,而不想要它的實現,那麼就試用implements

class Implements {
  
  void base() {
    print('base');
  }
    
  void log() {
    print('extends');
  }
  
}

class Log implements Implements {
  
  base() {
    print('log#base');
  }
  
  log() {
    print('log');
  }
  
}

void main() {
  Log().base();
  Log().log();
}
複製代碼

輸出結果:

log#base
log
複製代碼

4、混入

前面咱們介紹的都是Java中接觸過的概念,下面咱們來介紹Dart中特有的概念 - 混入。

4.1 mixin

mixin用於修飾類,和abstract相似,該類能夠擁有成員變量、普通方法、抽象方法,可是不能夠實例化。mixin通常用於描述一種具備某種功能的組塊,而某一對象能夠擁有多個不一樣功能的組塊。

(1) 最簡單

最簡單的mixinmixin & with關鍵字組成。

舉個例子,咱們有一種能力是 '繪畫',而擁有這種能力的是 ‘教師’,那麼實現以下:

mixin DrawFunc {
  
  String content = '..';
  
  String what();
    
  void draw() {
    print('I can draw ${what()}');  
  }
  
}

class Teacher with DrawFunc {
  
  String what() => "car";
  
}

void main() {
  Teacher().draw();
}
複製代碼

(2) 限定類型

咱們限定了 '繪畫' 這種能力只可以用在 '人類' 上面,示例以下:

class Person {}

mixin DrawFunc on Person {
  
  String content = '..';
  
  String what();
    
  void draw() {
    print('I can draw ${what()}');  
  }
  
}

class Teacher extends Person with DrawFunc {
  
  String what() => "car";
  
}

void main() {
  Teacher().draw();
}
複製代碼

當咱們在mixin上使用了on關鍵字,那麼mixin只能在那個類的子類上使用,而mixin能夠調用那個類的方法。

(3) 多個類型

在 '繪畫' 的基礎上,咱們增長一種新的能力 '唱歌',示例以下:

class Person {}

mixin DrawFunc on Person {
  
  String content = '..';
  
  String what();
    
  void draw() {
    print('I can draw ${what()}');  
  }
  
}

mixin SingFunc on Person {
  
  void sing() {
    print('I can sing');
  }
}

class Teacher extends Person with DrawFunc, SingFunc {
  
  String what() => "car";
  
}

void main() {
  Teacher().draw();
  Teacher().sing();
}
複製代碼

(4) on 的一種複雜變形

關於on還有一種複雜的變形,咱們在 '唱歌' 上增長一條約束,要求它必須是在DrawFunc之上:

mixin SingFunc on Person, DrawFunc {
  
  void sing() {
    print('I can sing');
  }
}
複製代碼

那麼這時候,雖然Teacher沒有extends DrawFunc,可是以下的代碼仍然能夠編譯經過:

class Teacher extends Person with DrawFunc, SingFunc {
  
  String what() => "car";
  
}
複製代碼

而咱們交換一下DrawFuncSingFunc的順序就不行了:

class Teacher extends Person with SingFunc, DrawFunc {
  
  String what() => "car";
  
}
複製代碼

提示信息是:

Error compiling to JavaScript:
main.dart:22:7:
Error: 'Person' doesn't implement 'DrawFunc' so it can't be used with 'SingFunc'.
 - 'Person' is from 'main.dart'.
 - 'DrawFunc' is from 'main.dart'.
 - 'SingFunc' is from 'main.dart'.
class Teacher extends Person with SingFunc, DrawFunc {
      ^
Error: Compilation failed.
複製代碼

結論:要知足on的要求,除了使用extends以外,還能夠在with列表中,在它以前進行聲明。在FlutterWidgetsFlutterBinding中,就涉及到了這一點的運用。

abstract class BindingBase {}

mixin ServicesBinding on BindingBase {}

mixin SchedulerBinding on BindingBase, ServicesBinding {}

mixin RendererBinding on BindingBase, ServicesBinding {}

class WidgetsFlutterBinding extends BindingBase with ServicesBinding, SchedulerBinding, RendererBinding {}
複製代碼

(5) Tips

在這上面,咱們接觸了幾個新的概念mixin, on, with

  • mixin:定義了組塊。
  • on:限定了使用mixin組塊的宿主必需要繼承於某個特定的類;在mixin中能夠訪問到該特定類的成員和方法。
  • with:負責組合組塊,而with後面跟的類並不必定須要是mixin的,abstract class和普通類都是能夠的,這一點須要注意,例以下面這樣:
class Person {}

mixin DrawFunc on Person {
  
  String content = '..';
  
  String what();
    
  void draw() {
    print('I can draw ${what()}');  
  }
  
}

mixin SingFunc on Person {
  
  void sing() {
    print('I can sing');
  }
}

abstract class DanceFunc {
  
  void dance() {
    print('I can dance');
  }
  
}

class Teacher extends Person with DrawFunc, SingFunc, DanceFunc {
  
  String what() => "car";
  
}

void main() {
  Teacher().draw();
  Teacher().sing();
  Teacher().dance();
}
複製代碼

4.2 衝突

若是同時存在extends, with,而且它們都定義了相同的方法名,那麼結果如何呢?咱們來看下面的例子:

class Extends {
  
  void log() {
    print('extends');
  }
  
}

mixin Mixins {
  
  void log() {
    print('mixin');
  }
  
}

mixin Mixins2 {
  
  void log() {
    print('mixin2');
  }
  
}

class Log extends Extends with Mixins, Mixins2 {}

void main() {
  Log().log();
}
複製代碼

輸出結果:

mixin2
複製代碼

結論

  • with修飾的會覆蓋extends中修飾的同名方法。
  • with列表中後一個的會覆蓋以前的。

再來看一下加上了implements的狀況。

class Extends {
  
  void log() {
    print('extends');
  }
  
}

mixin Mixins {
  
  void log() {
    print('mixin');
  }
  
}

mixin Mixins2 {
  
  void log() {
    print('mixin2');
  }
  
}

class Implements {
  
  void log() {
    print('implements');
  }
  
}

class Log extends Extends with Mixins, Mixins2 implements Implements {}

void main() {
  Log().log();
}
複製代碼

輸出結果爲:

mixin2
複製代碼

這裏咱們發現了一個奇怪的現象:雖然咱們加上了implements,可是Dart竟然沒讓咱們實現Implements.log()方法!

這是由於在這種狀況下,它識別到咱們從withextends中得到了log()方法的能力,所以調用的是Mixins2.log()

假如咱們對Implements#log方法進行實現:

class Log extends Extends with Mixins, Mixins2 implements Implements {
  
  void log() {
    print("implements log");
  }
}
複製代碼

輸出的結果爲:

implements log
複製代碼

5、小結

梳理下來,有幾點感想:

  • 以前咱們設計中用到了interface的部分,能夠採用只帶有抽象方法的abstract class替換,並繼續使用implements關鍵字。
  • 理解mixin的概念,我是將它理解爲一個個的功能組塊:哪些宿主須要哪些功能,我就with到上去。
  • on關鍵字一方面是爲了限制組塊的應用場景,也能夠爲多個組塊提供公共的基礎功能。

參考資料

相關文章
相關標籤/搜索