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

一掂林、前言

在使用Java語(yǔ)言設(shè)計(jì)類(lèi)之間關(guān)系的時(shí)候志鞍,我們會(huì)接觸到 組成單元關(guān)系連接 這兩類(lèi)概念:

  • 組成單元:普通類(lèi)聂薪、abstract抽象類(lèi)家乘,interface接口。
  • 關(guān)系連接:implements實(shí)現(xiàn)藏澳,extends繼承仁锯。

而在Dart當(dāng)中,對(duì)于這兩類(lèi)概念進(jìn)行了增減:

  • 組成單元:普通類(lèi)翔悠,abstract抽象類(lèi)业崖、mixin野芒。
  • 關(guān)系連接:implements實(shí)現(xiàn)、extends繼承双炕、with混入复罐。

最大的不同有兩點(diǎn):

  • 去掉了interface
  • 增加了混入的概念雄家。

下面我們就來(lái)看一下其中涉及到的知識(shí)點(diǎn)效诅,前面兩節(jié)對(duì)比一下JavaDart的區(qū)別,最后著重介紹混入的概念趟济。

推薦給大家一個(gè)網(wǎng)站:https://dartpad.dartlang.org/ 可以在線(xiàn)運(yùn)行乱投。

二、組成單元

2.1 普通類(lèi)

JavaDart的普通類(lèi)有區(qū)別顷编,但是不影響我們?cè)O(shè)計(jì)類(lèi)之間的關(guān)系戚炫,因此不再贅述。

2.2 abstract 抽象類(lèi)

JavaDart的抽象類(lèi)定義時(shí)大體是一樣的媳纬,我們可以在其中定義變量双肤、普通方法、抽象方法钮惠,它和普通類(lèi)最大的區(qū)別就是 抽象類(lèi)不能實(shí)例化茅糜。

JavaDart在使用抽象類(lèi)時(shí)有一點(diǎn)不同:Dart在定義抽象方法時(shí),不需要用abstract修飾素挽。

abstract class DartAbs {
  
  void absMethod();
  
}

2.3 interface 接口

Dart中蔑赘,沒(méi)有 interface 關(guān)鍵字

順帶我們復(fù)習(xí)一下Javaabstractinterface的一些要點(diǎn):

  • 抽象類(lèi)和接口都不能被實(shí)例化预明。
  • 抽象類(lèi)要被子類(lèi)繼承缩赛,接口要被類(lèi)實(shí)現(xiàn)。
  • 接口只能做方法的聲明撰糠,抽象類(lèi)可以做方法的聲明酥馍,也可以做方法的實(shí)現(xiàn)。
  • 接口里定義的變量只能是公共的靜態(tài)常量阅酪,抽象類(lèi)中的變量可以是普通變量旨袒。
  • 抽象類(lèi)里的抽象方法必須全部被子類(lèi)實(shí)現(xiàn);接口的接口方法必須全部被子類(lèi)實(shí)現(xiàn)遮斥,否則只能為抽象類(lèi)峦失。
  • 抽象類(lèi)里可以沒(méi)有抽象方法。
  • 如果一個(gè)類(lèi)里有抽象方法术吗,那么這個(gè)類(lèi)只能是抽象類(lèi)尉辑。
  • 抽象方法要被實(shí)現(xiàn),所以不能是靜態(tài)的较屿,也不能是私有的隧魄。
  • 接口可繼承接口卓练,并可多繼承接口,但類(lèi)只能單繼承购啄。

三襟企、關(guān)系連接

3.1 extends

JavaDartextends是一致的,只可以單繼承狮含,要注意的點(diǎn)是:

  • 子類(lèi)可以繼承父類(lèi)里面 可見(jiàn)的屬性和方法顽悼。
    • 對(duì)于Java來(lái)說(shuō),可見(jiàn)指的是非private修飾几迄,
    • 對(duì)Dart來(lái)說(shuō)蔚龙,指的是非下劃線(xiàn)_開(kāi)頭。
  • 子類(lèi)調(diào)用父類(lèi)的方法映胁,使用super關(guān)鍵字木羹。
  • 子類(lèi)不會(huì) 繼承 父類(lèi)的構(gòu)造函數(shù)。
class Extends {
  
  void base() {
    print('base');
  }
  
  void log() {
    print('extends');
  }
  
}

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

void main() {
  Log().base();
  Log().log();
}

輸出結(jié)果:

base
log

3.2 implements

implementsextends最大的不同就是允許后面接上多個(gè)普通或者抽象類(lèi)解孙,當(dāng)我們使用B implement A修飾時(shí)坑填,那么A中的所有的屬性和方法都要在A中實(shí)現(xiàn),無(wú)論它原來(lái)是抽象方法還是普通方法弛姜。

也就是說(shuō)如果我們只想要A中的接口定義脐瑰,而不想要它的實(shí)現(xiàn),那么就試用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();
}

輸出結(jié)果:

log#base
log

四蚪黑、混入

前面我們介紹的都是Java中接觸過(guò)的概念,下面我們來(lái)介紹Dart中特有的概念 - 混入中剩。

4.1 mixin

mixin用于修飾類(lèi),和abstract類(lèi)似抒寂,該類(lèi)可以擁有成員變量结啼、普通方法、抽象方法屈芜,但是不可以實(shí)例化郊愧。mixin一般用于描述一種具有某種功能的組塊,而某一對(duì)象可以擁有多個(gè)不同功能的組塊井佑。

(1) 最簡(jiǎn)單

最簡(jiǎn)單的mixinmixin & with關(guān)鍵字組成属铁。

舉個(gè)例子,我們有一種能力是 '繪畫(huà)'躬翁,而擁有這種能力的是 ‘教師’焦蘑,那么實(shí)現(xiàn)如下:

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) 限定類(lèi)型

我們限定了 '繪畫(huà)' 這種能力只能夠用在 '人類(lèi)' 上面,示例如下:

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();
}

當(dāng)我們?cè)?code>mixin上使用了on關(guān)鍵字盒发,那么mixin只能在那個(gè)類(lèi)的子類(lèi)上使用例嘱,而mixin可以調(diào)用那個(gè)類(lèi)的方法狡逢。

(3) 多個(gè)類(lèi)型

在 '繪畫(huà)' 的基礎(chǔ)上,我們?cè)黾右环N新的能力 '唱歌'拼卵,示例如下:

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 的一種復(fù)雜變形

關(guān)于on還有一種復(fù)雜的變形奢浑,我們?cè)?'唱歌' 上增加一條約束,要求它必須是在DrawFunc之上:

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

那么這時(shí)候腋腮,雖然Teacher沒(méi)有extends DrawFunc雀彼,但是如下的代碼仍然可以編譯通過(guò):

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.

結(jié)論:要滿(mǎn)足on的要求,除了使用extends之外即寡,還可以在with列表中详羡,在它之前進(jìn)行聲明。在FlutterWidgetsFlutterBinding中嘿悬,就涉及到了這一點(diǎn)的運(yùn)用实柠。

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

在這上面,我們接觸了幾個(gè)新的概念mixin, on, with

  • mixin:定義了組塊善涨。
  • on:限定了使用mixin組塊的宿主必須要繼承于某個(gè)特定的類(lèi)窒盐;在mixin中可以訪(fǎng)問(wèn)到該特定類(lèi)的成員和方法。
  • with:負(fù)責(zé)組合組塊钢拧,而with后面跟的類(lèi)并不一定需要是mixin的蟹漓,abstract class和普通類(lèi)都是可以的,這一點(diǎn)需要注意源内,例如下面這樣:
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 沖突

如果同時(shí)存在extends, with葡粒,并且它們都定義了相同的方法名,那么結(jié)果如何呢膜钓?我們來(lái)看下面的例子:

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();
}

輸出結(jié)果:

mixin2

結(jié)論

  • with修飾的會(huì)覆蓋extends中修飾的同名方法嗽交。
  • with列表中后一個(gè)的會(huì)覆蓋之前的。

再來(lái)看一下加上了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();
}

輸出結(jié)果為:

mixin2

這里我們發(fā)現(xiàn)了一個(gè)奇怪的現(xiàn)象:雖然我們加上了implements夫壁,但是Dart居然沒(méi)讓我們實(shí)現(xiàn)Implements.log()方法!

這是因?yàn)樵谶@種情況下沃疮,它識(shí)別到我們從withextends中獲得了log()方法的能力盒让,因此調(diào)用的是Mixins2.log()

假如我們對(duì)Implements#log方法進(jìn)行實(shí)現(xiàn):

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

輸出的結(jié)果為:

implements log

五司蔬、小結(jié)

梳理下來(lái)邑茄,有幾點(diǎn)感想:

  • 之前我們?cè)O(shè)計(jì)中用到了interface的部分,可以采用只帶有抽象方法的abstract class替換俊啼,并繼續(xù)使用implements關(guān)鍵字肺缕。
  • 理解mixin的概念,我是將它理解為一個(gè)個(gè)的功能組塊:哪些宿主需要哪些功能,我就with到上去搓谆。
  • on關(guān)鍵字一方面是為了限制組塊的應(yīng)用場(chǎng)景炒辉,也可以為多個(gè)組塊提供公共的基礎(chǔ)功能。

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末泉手,一起剝皮案震驚了整個(gè)濱河市黔寇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌斩萌,老刑警劉巖缝裤,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異颊郎,居然都是意外死亡憋飞,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)姆吭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)榛做,“玉大人,你說(shuō)我怎么就攤上這事内狸〖烀校” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵昆淡,是天一觀的道長(zhǎng)锰瘸。 經(jīng)常有香客問(wèn)我,道長(zhǎng)昂灵,這世上最難降的妖魔是什么避凝? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮眨补,結(jié)果婚禮上管削,老公的妹妹穿的比我還像新娘。我一直安慰自己渤涌,他們只是感情好佩谣,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著实蓬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吊履。 梳的紋絲不亂的頭發(fā)上安皱,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音艇炎,去河邊找鬼酌伊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的居砖。 我是一名探鬼主播虹脯,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼奏候!你這毒婦竟也來(lái)了循集?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蔗草,失蹤者是張志新(化名)和其女友劉穎咒彤,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體咒精,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡镶柱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了模叙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片歇拆。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖范咨,靈堂內(nèi)的尸體忽然破棺而出故觅,到底是詐尸還是另有隱情,我是刑警寧澤湖蜕,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布逻卖,位于F島的核電站,受9級(jí)特大地震影響昭抒,放射性物質(zhì)發(fā)生泄漏评也。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一灭返、第九天 我趴在偏房一處隱蔽的房頂上張望盗迟。 院中可真熱鬧,春花似錦熙含、人聲如沸罚缕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)邮弹。三九已至,卻和暖如春蚓聘,著一層夾襖步出監(jiān)牢的瞬間腌乡,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工夜牡, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留与纽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像急迂,于是被迫代替她去往敵國(guó)和親影所。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345