0x00 前言
mixins
作為Flutter的重要特性,值得好好研究一下
0x01 mixins的定義
mixins
的中文意思是混入,就是在類中混入其他功能。
Dart中的定義是:
Mixins are a way of reusing a class’s code in multiple class hierarchies.
複製程式碼
Mixins是一種在多個類層次結構中複用類程式碼的方法。
可以看出Mixins最重要的功能是複用程式碼,我們先看下JAVA,複用程式碼的方式有哪些:
-
繼承
子類可以複用父類的方法和屬性,但是JAVA裡的繼承只能單繼承。
-
組合
將要複用的程式碼,封裝成類A,讓其他類持有A的例項,看上去貌似解決了複用程式碼的問題,但是一方面,每個類持有的A的例項是不同的,有多少個類,就總共有多少個A的例項,而且另一方面,即使A使用單例,使用起來也很不方便。
-
介面 定義一個介面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的功能,但是需要強調的是:
- mixins的物件是類
- mixins絕不是繼承,也不是介面,而是一種全新的特性
- 可以mixins多個類
- mixins的使用需要滿足一定條件
0x02 with
mixins要用到的關鍵字 with
怎麼來理解with
呢?很簡單:
繼承 -> extends
mixins -> with
繼承和mixins是一樣的,是語言的特性,with和extends是關鍵字。
0x03 使用mixins的條件
因為mixins使用的條件,隨著Dart版本一直在變,這裡講的是Dart2.1中使用mixins的條件:
- mixins類只能繼承自object
- mixins類不能有建構函式
- 一個類可以mixins多個mixins類
- 可以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的用法與區別
- on 一個類
用繼承:
lass A {
void a(){
print("a");
}
}
mixin X on A{
void x(){
print("x");
}
}
class mixinsX extends A with X{
}
複製程式碼
- 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{
}
複製程式碼