flutter 關(guān)于abstract抽象類旅掂、mixins混入、implements接口實現(xiàn)

前言:
最近看了很多關(guān)于標(biāo)題的文章访娶,忙里偷閑總結(jié)一下自己的理解商虐,這篇文章的總結(jié)不會很全面的解釋各個名詞的概念,而是針對我個人覺著大家容易遺漏混淆的點崖疤,或者比較重要的點的一個總結(jié)秘车。如果對概念都不清晰的朋友可先自行百度了解。
ps:有不對的地方還請大家指正劫哼,謝謝叮趴。
ps:今天又看到一篇關(guān)于這塊內(nèi)容不錯的文章- http://www.reibang.com/p/863c531380cd

  • abstract 抽象類

1、抽象類不能被實例化权烧,只有繼承它的子類可以眯亦。
2、抽象類中一般我們把沒有方法體的方法稱為抽象方法般码。
3妻率、子類繼承抽象類必須實現(xiàn)它的抽象方法。
4板祝、如果把抽象類當(dāng)做接口實現(xiàn)的話必須得實現(xiàn)抽象類里面定義的所有屬性和方法宫静。

  • mixins 混入

1、mixin用于修飾類券时,和abstract類似囊嘉,該類可以擁有成員變量、普通方法革为、抽象方法扭粱,但是不可以實例化。
2震檩、mixin一般用于描述一種具有某種功能的組塊琢蛤,而某一對象可以擁有多個不同功能的組塊蜓堕。

  • mixin:定義了組塊。
  • on:限定了使用mixin組塊的宿主必須要繼承于某個特定的類博其;在mixin中可以訪問到該特定類的成員和方法套才。
  • with:負(fù)責(zé)組合組塊,而with后面跟的類并不一定需要是mixin的慕淡,abstract class和普通類都是可以的背伴,這一點需要注意

混入的一些基本概念與作用的理解可以參考https://blog.csdn.net/HuberCui/article/details/93468810

下面用一些實際的例子來加深我們的理解:

在我們開發(fā)多屏app的時候,我們更傾向于復(fù)用一些類的代碼去完成一些功能峰髓,讓代碼能夠“高復(fù)用”傻寂,比如:全局錯誤提示、頁面的公共視圖部分的復(fù)用携兵、響應(yīng)式編程(Bloc)里面的依賴邏輯等疾掰。使用抽象類abstract基本上就能完成這些功能,但是問題來了徐紧,如果頁面上的公共部分我不想用到所有頁面静檬,只想在特定的頁面上用,那該怎么辦呢? 比如AppBar, 部分頁面不需要公共的并级,而需要自定義拂檩,因為一個class類只能是一個類的子類,而我們需要更靈活的類的組合嘲碧,這就是我們?yōu)槭裁葱枰猰ixin广恢。
ps:本段轉(zhuǎn)自http://www.reibang.com/p/7e14ed414dce,這是我覺得很好的一篇關(guān)于mixins實踐的文章呀潭。

1钉迷、flutter中的繼承是單繼承,使用mixins相當(dāng)于變相的實現(xiàn)了多繼承钠署。
2糠聪、由于mixins通過代碼更好理解它的含義與用法,上代碼谐鼎!

mixin到底是怎么用的舰蟆?讓我們先舉一個例子,新建一個abstract class Person
abstract class Person {
  void think() {
    print("Hmm, I wonder what I can do today");
  }
}

我們可以用extend關(guān)鍵字把這個類作為父類來使用狸棍,比如:
class Mike extends Person {} //由于person類里并不是抽象方法稽荧,我們可以不實現(xiàn)或者重寫

void main() {
  var mike = Mike();
  mike.think(); // prints: "Hmm, I wonder what I can do today"
}

但是我們要這么給Mike添加一些其他“新功能”呢粒蜈?比如Mike是一位 coder 郎仆,他有coder的一些特性炕婶,但不是所有人都有,該怎么辦呢唐片? mixin就能解決這個問題丙猬。
首先涨颜,我們需要創(chuàng)建一個mixin類并添加一我們需要的新的方法:
mixin Coder {
  void code() {
    print("Coding intensifies");
  }
}

使用關(guān)鍵字with,我們能將這個“新功能”添加給Mike:
class Mike extends Person with Coder {}

并且,與父類一樣茧球,我們可以調(diào)用在Coder中創(chuàng)建的所有函數(shù):
void main() {
  var mike = Mike();
  mike.code(); // prints: "Coding intensifies"
}

現(xiàn)在庭瑰,每一個使用 mixin coder的類都擁有coder的方法,然而這帶來了一個問題:這意味著抢埋,如果我們有一個帶有子級Squirrel的父類Animal弹灭,那么我們也可以擁有一個可以code()方法的Squirrel!為了防止這種情況揪垄,我們可以使用關(guān)鍵字on將mixin的使用“鎖定”到一個類以及從該類繼承的所有類:
mixin Coder on Person{
  void code() {
    print("Coding intensifies");
  }
}

這相當(dāng)于為我們提供了一個強大的工具:現(xiàn)在我們可以覆蓋重寫在Person類中設(shè)置的方法用來添加或擴展其功能穷吮。
mixin Coder on Person{
  //...

  @override
  void think() {
    super.think();
    print("I'm going to code today!");
  }
}

調(diào)用super.think()可確保我們?nèi)匀豢梢哉{(diào)用Person中定義的代碼,上面的代碼擴展了Mike類的think()方法將會輸出:
Hmm, I wonder what I can do today
I'm going to code today!
  • 接下來用一個開發(fā)中可能會經(jīng)常遇到的情景來加深我們的理解

mixins 與 基礎(chǔ)類:一個實際的常用例子

先試著想一下這種情況我們在flutter app中應(yīng)該怎么做:
在app中我們有兩個頁面是這樣的:

image.png

我們的app有幾個屏幕如上面顯示的那樣福侈。我們想共用每個屏幕的AppBar和background酒来,我們可以使用mixin解決問題卢未。

在這種情況下肪凛,我們都定義了屏幕標(biāo)題,我們將創(chuàng)建一個基類辽社,該基類具有一種提供屏幕名稱的方法伟墙,該基類稱為BasePage。我們也將僅在StatefulWidgets中應(yīng)用mixins滴铅,因為我們的類將維護并更改其狀態(tài)戳葵。這樣,我們創(chuàng)建了兩個用于頁面的類:BasePage和BaseState <BasePage>分別繼承StatefulWidget和State <StatefulWidget>汉匙。

abstract class BasePage extends StatefulWidget {
  BasePage({Key key}) : super(key: key);
}

// TODO: Page為命名泛型 繼承 BasePage,    BaseState作為抽象基類拱烁,也會被子類繼承,所以傳入泛型限制參數(shù)類型
abstract class BaseState<Page extends BasePage> extends State<Page> {
  String screenName();
}

我們現(xiàn)在創(chuàng)建一個自定義mixin BasicPageMixin噩翠,在其中定義頁面的背景和標(biāo)題名稱戏自。

// TODO: BasicPage 是一個mixin,作用于BaseState和其基類, 抽取渲染頁面公共部分
mixin BasicPage<Page extends BasePage> on BaseState<Page> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(screenName()),
        ),
        body: Container(
          child: body(),
          color: Colors.amber,
        ));
  }

  Widget body();
}
由于body()方法沒有實例,因此使用此mixin的每個類都必須實現(xiàn)它伤锚,以確保我們不會忘記在頁面中添加body()擅笔。

在屏幕上面我們看到了FloatingActionButton,但是我們不是每個屏幕都需要展示它屯援,該怎么辦呢猛们?我們可以聲明一個新方法fab(),默認(rèn)的渲染輸出一個空的Container狞洋。如果繼承的子類需要它弯淘,那么子類可以通過@override重寫fab()來添加一個FloatingActionButton。

  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(screenName()),
        ),
        body: Container(
          child: body(),
          color: Colors.amber,
        ));
        floatingActionButton: fab(),
  }
   
  // NOTE: 這里沒有在基類中初始化是因為渲染wedget 盡量寫在子組件state中, 更好的狀態(tài)管理,更好的性能
  // TODO: body()子類必須實現(xiàn)
  Widget body();
  // TODO: fab()子類可選實現(xiàn)
  Widget fab() => Container();
}

我們的mixin 已經(jīng)創(chuàng)建好了吉懊, 我們來通過它新建一個頁面:

class MyMixinHomePage extends BasePage {
  MyMixinHomePage({Key key}) : super(key: key);
  @override
  _MyMixinHomePageState createState() => _MyMixinHomePageState();
}

class _MyMixinHomePageState extends BaseState<MyMixinHomePage> with BasicPage{
  @override
  String screenName() => "Home";

  @override
  Widget body() {
    return Center(child: Text("This is a basic usage of a mixin"));
  }
}

有了這個耳胎,我們現(xiàn)在只需要聲明一個body()和一個可能在屏幕中使用的fab()小部件惯吕,從而節(jié)省了幾十行代碼。very nice !

  • implements 接口實現(xiàn)

1怕午、implements與extends最大的不同就是允許后面接上多個普通或者抽象類废登,當(dāng)我們使用B implement A修飾時,那么A中的所有的屬性和方法都要在A中實現(xiàn)郁惜,無論它原來是抽象方法還是普通方法堡距。

2、如果我們只想要A中的接口定義兆蕉,而不想要它的實現(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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市包蓝,隨后出現(xiàn)的幾起案子驶社,更是在濱河造成了極大的恐慌,老刑警劉巖测萎,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亡电,死亡現(xiàn)場離奇詭異,居然都是意外死亡硅瞧,警方通過查閱死者的電腦和手機份乒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來腕唧,“玉大人或辖,你說我怎么就攤上這事≡娼樱” “怎么了颂暇?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長月腋。 經(jīng)常有香客問我蟀架,道長,這世上最難降的妖魔是什么榆骚? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任片拍,我火速辦了婚禮,結(jié)果婚禮上妓肢,老公的妹妹穿的比我還像新娘捌省。我一直安慰自己,他們只是感情好碉钠,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布纲缓。 她就那樣靜靜地躺著卷拘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪祝高。 梳的紋絲不亂的頭發(fā)上栗弟,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音工闺,去河邊找鬼乍赫。 笑死,一個胖子當(dāng)著我的面吹牛陆蟆,可吹牛的內(nèi)容都是我干的雷厂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼叠殷,長吁一口氣:“原來是場噩夢啊……” “哼改鲫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起林束,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤像棘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后诊县,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讲弄,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡措左,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年依痊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怎披。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡胸嘁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出凉逛,到底是詐尸還是另有隱情性宏,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布状飞,位于F島的核電站毫胜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏诬辈。R本人自食惡果不足惜酵使,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望焙糟。 院中可真熱鬧口渔,春花似錦、人聲如沸穿撮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至攻礼,卻和暖如春业踢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背礁扮。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工陨亡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人深员。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓负蠕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親倦畅。 傳聞我的和親對象是個殘疾皇子遮糖,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345