主頁 > 後端開發 > Flutter 中不得不會的 mixin

Flutter 中不得不會的 mixin

2021-02-23 06:12:10 後端開發

mixin 是 Dart 中非常重要的概念,對于未接觸過此概念的Coder來說尤其重要,最近看原始碼的時候,由于對 mixin 不熟悉導致理解出現偏差,走了很多彎路,所以這篇文章介紹一下 mixin 概念,

Dart 及 Engine 版本:

Engine ? revision ae90085a84
Tools ? Dart 2.10.4

請注意版本,不同的版本可能存在差異,

先來看下官方的定義:

Mixins are a way of reusing a class’s code in multiple class hierarchies.

Mixins 是一種在多個類層次結構中重用類代碼的方法,

在來看下 Wiki 的解釋:

In object-oriented programming languages, a mixin (or mix-in) is a class that contains methods for use by other classes without having to be the parent class of those other classes. How those other classes gain access to the mixin's methods depends on the language. Mixins are sometimes described as being "included" rather than "inherited".

Mixins encourage code reuse and can be used to avoid the inheritance ambiguity that multiple inheritance can cause (the "diamond problem"), or to work around lack of support for multiple inheritance in a language. A mixin can also be viewed as an interface with implemented methods. This pattern is an example of enforcing the dependency inversion principle.

翻譯如下:

在面向物件的編程語言中,mixin(或mix-in)是一個類,其中包含供其他類使用的方法,而不必成為其他類的父類, 這些其他類如何獲得對mixin方法的訪問權限取決于語言, 混合素有時被描述為“包含”而不是“繼承”,

Mixins鼓勵代碼重用,并且可用于避免多重繼承可能導致的繼承歧義(“鉆石問題”),或解決語言中對多重繼承的支持不足的問題, 混合也可以看作是已實作方法的介面, 此模式是強制執行依賴關系反轉原理的示例,

看完這兩段介紹,可能依然對其比較模糊,不要緊,現在只需對其有個概念即可,下面會詳細介紹 Mixins 的用法,我個人的理解就是:Mixins 解決了無法多重繼承的問題,

什么時候需要使用 Mixins

有如下場景:

定義一個基類人(Person),它有吃(eat)的方法,

有3個實際的人A、B、C,它們都繼承 Person,但是3個人有不同的技能:

  • A :會唱歌、跳舞
  • B:會跳舞、寫代碼
  • C:會唱歌、寫代碼

上面的場景中唱歌、跳舞、寫代碼是一種技能,并不是每一個人都會的,所以將其定義在 Person 中是不合適的,如果各自定義為一個類,又不能同時繼承Person和唱歌、跳舞、寫代碼,如果將唱歌、跳舞、寫代碼定義為 Interface ,那么A、B、C中要各自實作其方法,

那要如何實作呢? Mixins 出場啦,

定義一個 Person 基類和功能類唱歌、跳舞、寫代碼:

class Person {
  eat() {
    print('Person eat');
  }
}

class Dance {
  dance() {
    print('Dance dance');
  }
}

class Sing {
  sing() {
    print('Sing sing');
  }
}

class Code {
  code() {
    print('Code code');
  }
}

定義A、B、C:

class A extends Person with Dance, Sing {}

class B extends Person with Sing, Code {}

class C extends Person with Code, Dance {}

注意:混合使用 with 關鍵字,

使用:

A a = A();
a.eat();
a.dance();
a.sing();

輸出日志:

flutter: Person eat
flutter: Dance dance
flutter: Sing sing

可以看到 A 中有了Dance 和Sing的相關的方法,

Dance 是一個 class,如果給其添加建構式會如何?

給 Dance 添加建構式,修改如下,

此時發現 A 和 C 無法編譯,出現如下錯誤:

很明顯,需要 mixin 的類無法定義建構式,

所以一般會將需要 mixin 的類使用 mixin 關鍵字:

添加限定條件,使用關鍵字 on

接著上面的場景繼續,這時定義一個狗的類,目前狗這個類也可以混合 Dance 、Sing 和 Code,

class Dog with Code{}

但是,Code 是人類獨有的技能,不希望 Dog 這個類可以mixin,所以給 Code 添加限定條件:

使用關鍵字 on 限定Code 只能被 Person 或者其子類 mixin,

此時 Dog 無法 mixin Code,

添加限定后,可以重寫其方法, Code 重寫 Person 的方法:

super 表示呼叫父類(Person)的方法,

如何處理多個類有同一方法的情況

假設有D 和 D1 兩個類,有同一個方法 d,E mixin D 和 D1:

此時,呼叫 e.d 方法:

E e = E();
e.d();

輸出:

flutter: D1 d

說明后面的將前面的覆寫了,調換下D 和 D1的順序:

class E with D1, D {}

輸出:

flutter: D d

此時在 E 中也添加 d 方法:

輸出:

flutter: E d

說明 E 中 方法覆寫了原來的,

E 中 d 方法可以呼叫 super.d()

輸出:

flutter: D d
flutter: E d

假設現在有F、G、H 三個類,都有 a 方法,

有如下定義的類:

那么下面會輸出什么值:

答案是:

flutter: G a

記住:混合類時,進行混合的多個類是線性的,這是他們共有方法不沖突的原因,混合的順序非常重要,因為它決定了混合時相同的方法的處理邏輯,

再次看下 FG 的混合情況:

FG 繼承 H,混合 F 和 G,對于相同方法的優先級為:G > F > H,因此共有方法 a,最后執行的是 G 類中的 a 方法,

那么如果 FG 中也有 a 方法會如何?

如果本身(FG)也存在相同的方法那么優先級:FG > G > F > H,super.a() 執行的是 G 中的 a 方法,

輸出結果:

flutter: G a
flutter: FG a

更復雜的來啦,請看如下混合關系:

BB 為一個抽象類,有一個建構式,其中執行 init 方法,GB 和 PB 為一個混合型別,限定了只有 BB 或者其子類才能混合,WFB 繼承 BB,并混合GB、PB,此時創建 WFB 物件,

WFB wfb = WFB();

輸出結果是什么?

flutter: BB Constructor
flutter: BB init
flutter: GB init
flutter: PB init

是不是很詫異,按照上面的邏輯不是應該只呼叫 PB 的 init 方法嗎?

你理解的沒有錯,的確只呼叫了PB 的 init 方法,但是 PB 的 init 方法中呼叫了super.init(),這個才是重點,PB 通過 super.init 呼叫到了GB中的 init 方法, GB 通過 super.init 呼叫到了 BB 中的 init 方法,所以最終輸出的就是上面的結果,

這個一定要理解其中的呼叫順序,因為的 Flutter Framework 的入口函式 runApp 中就是此形式:

WidgetsFlutterBinding.ensureInitialized 方法如下:

WidgetsFlutterBinding 混合結構如下:

class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {

BindingBase 及建構式如下:

其執行了 initInstances 和 initServiceExtensions 方法,看下面混合的順序:

從后到前依次執行其 initInstances 和 initServiceExtensions(如果有) 方法,由于 initInstances 和 initServiceExtensions 方法中首先執行 super.initInstances()super.initServiceExtensions() ,所以最后執行的順序為:BindingBase -> GestureBinding -> SchedulerBinding -> ServicesBinding -> PaintingBinding -> SemanticsBinding -> RendererBindinsg -> WidgetsBinding ,

型別

還是上面的F、G、H 三個類,那么 FG 的型別是什么,看下面的判斷會輸出什么?

輸出:

flutter: FG is F : true
flutter: FG is G : true
flutter: FG is H : true

所以混合后的型別是超類的子型別,

總結

  1. Mixins 使我們可以在無需繼承父類的情況下為此類添加父類的“功能”,可以在同一個類中具有一個父級和多個 mixin 組件,
  2. Mixins 不可以宣告任何建構式,
  3. Mixins 添加限定條件使用 on 關鍵字,
  4. 混合使用 with 關鍵字,with 后面可以是 classabstract classmixin 的型別,
  5. Mixins 不是多重繼承,相反,它只是在多個層次結構中重用類中的代碼而無需擴展它們的一種方式,

交流

老孟Flutter博客(330個控制元件用法+實戰入門系列文章):http://laomengit.com

添加微信或者公眾號領取 《330個控制元件大全》和 《Flutter 實戰》PDF,

歡迎加入Flutter交流群(微信:laomengit)、關注公眾號【老孟Flutter】:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/262346.html

標籤:Dart

上一篇:C/C++編程學習:百行代碼實作小游戲(剪刀石頭布)

下一篇:now-go時間百寶箱

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more