Flutter Dart mixins 探究

小德_koude發表於2019-01-20

0x00 前言

mixins作為Flutter的重要特性,值得好好研究一下

0x01 mixins的定義

mixins的中文意思是混入,就是在類中混入其他功能。

Dart中的定義是:

Mixins are a way of reusing a class’s code in multiple class hierarchies.
複製程式碼

Mixins是一種在多個類層次結構中複用類程式碼的方法。

可以看出Mixins最重要的功能是複用程式碼,我們先看下JAVA,複用程式碼的方式有哪些:

  1. 繼承

    子類可以複用父類的方法和屬性,但是JAVA裡的繼承只能單繼承。

  2. 組合

    將要複用的程式碼,封裝成類A,讓其他類持有A的例項,看上去貌似解決了複用程式碼的問題,但是一方面,每個類持有的A的例項是不同的,有多少個類,就總共有多少個A的例項,而且另一方面,即使A使用單例,使用起來也很不方便。

  3. 介面 定義一個介面interface,類實現interface,這樣雖然介面是同一個,但是實現卻是分散的,能複用的程式碼是有限的。

所以在JAVA裡想要複用程式碼,限制是很多的。

這就有了mixins的概念,mixins最早的根源來自於Lisp,因為Dart也受到smalltakk的影響,所以Dart引入了mixins的概念,

在維基百科中有對mixins最準確的定義:

在物件導向的語言中,mixins類是一個可以把自己的方法提供給其他類使用,但卻不需要成為其他類的父類。
複製程式碼

mixins是要通過非繼承的方式來複用類中的程式碼。

這裡舉個例子,有一個類A,A中有一個方法a(),還有一個方法B,也想使用a()方法,而且不能用整合,那麼這時候就需要用到mixins,類A就是mixins類(混入類),類B就是要被mixins的類,對應的Dart程式碼如下:

類A mixins 到 B

class A {
  String content = 'A Class';

  void a(){
    print("a");
  }
}

class B with A{

}

B b = new B();
print(b.content);
b.a();
複製程式碼

輸出是:

A Class
a
複製程式碼

將類A mixins 到 B,B可以使用A的屬性和方法,B就具備了A的功能,但是需要強調的是:

  1. mixins的物件是類
  2. mixins絕不是繼承,也不是介面,而是一種全新的特性
  3. 可以mixins多個類
  4. mixins的使用需要滿足一定條件

0x02 with

mixins要用到的關鍵字 with

怎麼來理解with呢?很簡單:

繼承 -> extends

mixins -> with

繼承和mixins是一樣的,是語言的特性,with和extends是關鍵字。

0x03 使用mixins的條件

因為mixins使用的條件,隨著Dart版本一直在變,這裡講的是Dart2.1中使用mixins的條件:

  1. mixins類只能繼承自object
  2. mixins類不能有建構函式
  3. 一個類可以mixins多個mixins類
  4. 可以mixins多個類,不破壞Flutter的單繼承

0x04 一個類可以mixins多個mixins類

看下面程式碼:

class A {
  void a(){
    print("a");
  }
}

class A1 {
  void a1(){
    print("a1");
  }
}

class B with A,A1{

}

B b = new B();
b.a();
b.a1();
複製程式碼

輸出是:

a
a1
複製程式碼

但是,如果A和A1的方法相同,而且調換A和A1的順序,在被mixins的類中實現同一個方法呢,看下面的程式碼:

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

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 = new B();
B1 b1 = new B1();
B2 b2 = new B2();
B3 b3 = new B3();
B4 b4 = new B4();
B5 b5 = new B5();



b.a();
b1.a();
b2.a();
b3.a();
b4.a();
b5.a();
複製程式碼

會是什麼樣的結果呢?

0x05 mixins的實現原理

Mixins in Dart work by creating a new class that layers the implementation of the mixin
on top of a superclass to create a new class — it is not “on the side” but “on top” of
the superclass, so there is no ambiguity in how to resolve lookups.
複製程式碼

class B3 extends C with A,A1{

}
複製程式碼

為例,可以分解為:

class CA = C with A;
class CAA1 = CA with A1;

class B3 extends CAA1{
    
}
複製程式碼

mixins不是多繼承

Mixins is not a way to get multiple inheritance in the classical sense. Mixins is a way to abstract and reuse a family of operations and state. It is similar to the reuse you get from extending a class, but it is compatible with single-inheritance because it is linear.
複製程式碼

所以輸出結果是:

a1
a
b2
a1
a
b5
複製程式碼

0x06 mixins型別

mixins的例項型別是什麼?

很簡單,mixins的型別就是其超類的子型別,所以:

B3 b3 = B3();
print(b3 is C);
print(b3 is A);
print(b3 is A1);
複製程式碼

都會為true

0x07 on

on關鍵字,之前是用於try catch,用於指定異常的型別的。

這次,on只能用於被mixins標記的類,例如mixins X on A,意思是要mixins X的話,得先介面實現或者繼承A。這裡A可以是類,也可以是介面,但是在mixins的時候用法有區別.

想看介面的請看我的這篇文章Flutter Dart語法(1):extends 、 implements 、 with的用法與區別

  1. on 一個類

用繼承:

lass A {
  void a(){
    print("a");
  }
}


mixin X on A{
  void x(){
    print("x");
  }
}


class mixinsX extends A with X{

}
複製程式碼
  1. on 的是一個介面:

得首先實現這個介面,然後再用mix

class A {
  void a(){
    print("a");
  }
}


mixin X on A{
  void x(){
    print("x");
  }
}

class implA implements A{
  @override
  void a() {
    // TODO: implement a
  }

}

class mixinsX2 extends implA with X{

}
複製程式碼

相關文章