在使用Java
語言設計類之間關係的時候,咱們會接觸到 組成單元 和 關係鏈接 這兩類概念:html
abstract
抽象類,interface
接口。implements
實現,extends
繼承。而在Dart
當中,對於這兩類概念進行了增減:函數
abstract
抽象類、mixin
。implements
實現、extends
繼承、with
混入。最大的不一樣有兩點:post
interface
。下面咱們就來看一下其中涉及到的知識點,前面兩節對比一下Java
和Dart
的區別,最後着重介紹混入的概念。學習
推薦給你們一個網站:dartpad.dartlang.org/ 能夠在線運行。網站
Java
和Dart
的普通類有區別,可是不影響咱們設計類之間的關係,所以再也不贅述。ui
Java
和Dart
的抽象類定義時大致是同樣的,咱們能夠在其中定義變量、普通方法、抽象方法,它和普通類最大的區別就是 抽象類不能實例化。spa
Java
和Dart
在使用抽象類時有一點不一樣:Dart
在定義抽象方法時,不須要用abstract
修飾。設計
abstract class DartAbs {
void absMethod();
}
複製代碼
在Dart
中,沒有 interface 關鍵字。code
順帶咱們複習一下Java
中abstract
和interface
的一些要點:htm
Java
和Dart
中extends
是一致的,只能夠單繼承,要注意的點是:
Java
來講,可見指的是非private
修飾,Dart
來講,指的是非下劃線_
開頭。super
關鍵字。class Extends {
void base() {
print('base');
}
void log() {
print('extends');
}
}
class Log extends Extends {
log() {
print('log');
}
}
void main() {
Log().base();
Log().log();
}
複製代碼
輸出結果:
base
log
複製代碼
implements
與extends
最大的不一樣就是容許後面接上多個普通或者抽象類,當咱們使用B implement A
修飾時,那麼A
中的全部的屬性和方法都要在A
中實現,不管它原來是抽象方法仍是普通方法。
也就是說若是咱們只想要A
中的接口定義,而不想要它的實現,那麼就試用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();
}
複製代碼
輸出結果:
log#base
log
複製代碼
前面咱們介紹的都是Java
中接觸過的概念,下面咱們來介紹Dart
中特有的概念 - 混入。
mixin
用於修飾類,和abstract
相似,該類能夠擁有成員變量、普通方法、抽象方法,可是不能夠實例化。mixin
通常用於描述一種具備某種功能的組塊,而某一對象能夠擁有多個不一樣功能的組塊。
最簡單的mixin
由mixin & with
關鍵字組成。
舉個例子,咱們有一種能力是 '繪畫',而擁有這種能力的是 ‘教師’,那麼實現以下:
mixin DrawFunc {
String content = '..';
String what();
void draw() {
print('I can draw ${what()}');
}
}
class Teacher with DrawFunc {
String what() => "car";
}
void main() {
Teacher().draw();
}
複製代碼
咱們限定了 '繪畫' 這種能力只可以用在 '人類' 上面,示例以下:
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();
}
複製代碼
當咱們在mixin
上使用了on
關鍵字,那麼mixin
只能在那個類的子類上使用,而mixin
能夠調用那個類的方法。
在 '繪畫' 的基礎上,咱們增長一種新的能力 '唱歌',示例以下:
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();
}
複製代碼
關於on
還有一種複雜的變形,咱們在 '唱歌' 上增長一條約束,要求它必須是在DrawFunc
之上:
mixin SingFunc on Person, DrawFunc {
void sing() {
print('I can sing');
}
}
複製代碼
那麼這時候,雖然Teacher
沒有extends DrawFunc
,可是以下的代碼仍然能夠編譯經過:
class Teacher extends Person with DrawFunc, SingFunc {
String what() => "car";
}
複製代碼
而咱們交換一下DrawFunc
和SingFunc
的順序就不行了:
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.
複製代碼
結論:要知足
on
的要求,除了使用extends
以外,還能夠在with
列表中,在它以前進行聲明。在Flutter
的WidgetsFlutterBinding
中,就涉及到了這一點的運用。
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 {}
複製代碼
在這上面,咱們接觸了幾個新的概念mixin, on, with
:
mixin
:定義了組塊。on
:限定了使用mixin
組塊的宿主必需要繼承於某個特定的類;在mixin
中能夠訪問到該特定類的成員和方法。with
:負責組合組塊,而with
後面跟的類並不必定須要是mixin
的,abstract class
和普通類都是能夠的,這一點須要注意,例以下面這樣: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();
}
複製代碼
若是同時存在extends, with
,而且它們都定義了相同的方法名,那麼結果如何呢?咱們來看下面的例子:
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();
}
複製代碼
輸出結果:
mixin2
複製代碼
結論
with
修飾的會覆蓋extends
中修飾的同名方法。with
列表中後一個的會覆蓋以前的。再來看一下加上了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();
}
複製代碼
輸出結果爲:
mixin2
複製代碼
這裏咱們發現了一個奇怪的現象:雖然咱們加上了implements
,可是Dart
竟然沒讓咱們實現Implements.log()
方法!
這是由於在這種狀況下,它識別到咱們從with
和extends
中得到了log()
方法的能力,所以調用的是Mixins2.log()
。
假如咱們對Implements#log
方法進行實現:
class Log extends Extends with Mixins, Mixins2 implements Implements {
void log() {
print("implements log");
}
}
複製代碼
輸出的結果爲:
implements log
複製代碼
梳理下來,有幾點感想:
interface
的部分,能夠採用只帶有抽象方法的abstract class
替換,並繼續使用implements
關鍵字。mixin
的概念,我是將它理解爲一個個的功能組塊:哪些宿主須要哪些功能,我就with
到上去。on
關鍵字一方面是爲了限制組塊的應用場景,也能夠爲多個組塊提供公共的基礎功能。