一坛悉、概念
“Mixins are a way of reusing a class’s code in multiple class hierarchies.” 混合是一種在多個(gè)類(lèi)層次結(jié)構(gòu)中重用類(lèi)代碼的方法坪创。
從概念上我們可以理解它是為了解決代碼重用的一種方式。學(xué)習(xí)java的小伙伴可能會(huì)想到interface甚脉,Dart中的類(lèi)都可以作為接口,這不是已經(jīng)有了
解決方案了嗎铆农?為什么還需要mixin呢牺氨?
二、使用
首先我們來(lái)解決上面提到的問(wèn)題墩剖,為什么要使用mixin猴凹。
我們很多語(yǔ)言都是采用了單繼承+接口多實(shí)現(xiàn)的方式,但是這種方式不能很好的適用于所有場(chǎng)景岭皂。
我們看下下面這個(gè)假設(shè)的例子:
我們通過(guò)上圖可以看出郊霎,這些學(xué)生都有一個(gè)共同的父類(lèi)Student,然后又有三個(gè)抽象子類(lèi):文科班學(xué)生爷绘,理科班學(xué)生书劝、藝術(shù)班學(xué)生。這些類(lèi)具有相同的行為和能力土至,但是有的類(lèi)又有自己獨(dú)有的行為和能力购对。比如文科、理科陶因、藝術(shù)班學(xué)生都可以上數(shù)學(xué)課程骡苞,
但是只有理科班學(xué)生可以上物理課程,文科班和藝術(shù)班學(xué)生可以上地理課程楷扬,物理班學(xué)生又不可以上地理課程解幽。那么問(wèn)題就出現(xiàn)了,部分具有相同能力和行為的子類(lèi)都要保留一份相同的代碼實(shí)現(xiàn)烘苹,比如文科班學(xué)生類(lèi)和藝術(shù)班學(xué)生類(lèi)都要實(shí)現(xiàn)一份上地理課的實(shí)現(xiàn)躲株,
就產(chǎn)生了冗余。這種單繼承模型下镣衡,無(wú)法把部分子類(lèi)具有相同行為能力抽象到基類(lèi)中徘溢,因?yàn)閷?duì)其它不具有此行為的子類(lèi)來(lái)說(shuō)是不合適的吞琐,例如把上地理課放在基類(lèi)student中,因此只能在各自子類(lèi)中實(shí)現(xiàn)然爆。
abstract class Student{
}
abstract class GeographyClass{
void goGeography();
}
abstract class MathClass{
void goMath();
}
abstract class PhysicsClass{
void goPhysics();
}
class ScienceStudent extends Student implements MathClass, GeographyClass {
@override
void goGeography() {
print("上地理課");
}
@override
void goMath() {
print("上數(shù)學(xué)課");
}
}
class LiberalStudent extends Student implements MathClass, PhysicsClass {
@override
void goMath() {
print("上數(shù)學(xué)課");
}
@override
void goPhysics() {
print("上物理課");
}
}
class ArtStudent extends Student implements MathClass, GeographyClass {
@override
void goGeography() {
print("上地理課");
}
@override
void goMath() {
print("上數(shù)學(xué)課");
}
}
從上述實(shí)現(xiàn)代碼中可以看出站粟,子類(lèi)中很多相同的冗余實(shí)現(xiàn)代碼。那么我們是不是想有一種方式可以解決這種冗余問(wèn)題曾雕,是的奴烙,mixin就能很好的解決這類(lèi)問(wèn)題。
下面是使用mixin改寫(xiě)后的代碼:
abstract class Student{}
mixin GeographyClass{
void goGeography() {
print("上地理課");
}
}
mixin MathClass{
void goMath() {
print("上數(shù)學(xué)課");
}
}
mixin PhysicsClass{
void goPhysics() {
print("上物理課");
}
}
class ScienceStudent extends Student with MathClass, GeographyClass {
}
class LiberalStudent extends Student with MathClass, PhysicsClass {
}
class ArtStudent extends Student with MathClass, GeographyClass {
}
改寫(xiě)后的代碼可以發(fā)現(xiàn)剖张,mixin很好得解決了代碼冗余問(wèn)題切诀。它能復(fù)用類(lèi)中的某個(gè)功能具體實(shí)現(xiàn),而不是像接口一樣需要類(lèi)去實(shí)現(xiàn)哪些能力搔弄。因此mixin多繼承模型很好解決了單繼承模型帶來(lái)的冗余問(wèn)題幅虑。
注意:對(duì)mixin關(guān)鍵字的支持是在Dart 2.1 版本引入的,早期的版本使用abstract class
來(lái)代替的顾犹。
其實(shí)在java8和Kotlin中為了解決代碼重復(fù)冗余問(wèn)題倒庵,使用了接口的default實(shí)現(xiàn)來(lái)解決這個(gè)問(wèn)題:
interface ITest {
default void test(){}
}
三、線(xiàn)性化
mixin是線(xiàn)性化的炫刷,這句話(huà)如何理解呢擎宝?首先我們看下下面的例子:
mixin TA {
void t() {
print("TA");
}
}
mixin TB {
void t() {
print("TB");
}
}
class TC {
void t() {
print("TC");
}
}
class Mix1 with TA, TB {//TB
}
class Mix2 with TB, TA {//TA
}
我們會(huì)得到如下結(jié)果:
TB
TA
此時(shí)你可能會(huì)總結(jié)得到規(guī)律,with后面多個(gè)類(lèi)中有相同的方法浑玛,會(huì)調(diào)用距離with關(guān)鍵字最遠(yuǎn)的類(lèi)中的方法绍申。下面我們得到結(jié)論:
mixin混入類(lèi)中時(shí),Dart中的Mixins通過(guò)創(chuàng)建一個(gè)新類(lèi)來(lái)實(shí)現(xiàn)顾彰,該類(lèi)將mixin的實(shí)現(xiàn)層疊在一個(gè)超類(lèi)之上以創(chuàng)建一個(gè)新類(lèi) 极阅,它不是“在超類(lèi)中”,而是在超類(lèi)的“頂部涨享。
聲明 mixin 的順序代表了繼承鏈的繼承順序筋搏,聲明在后面的 mixin,一般會(huì)最先執(zhí)行灰伟。
接下來(lái)我們?cè)倏聪旅娴睦樱?/p>
class T {
void fun() {
print("A");
}
}
mixin TA on T{
void fun() {
super.fun();
cover();
print("TA");
}
void cover() {
print("cover TA");
}
}
mixin TB on T {
void fun() {
super.fun();
print("TB");
}
void cover() {
print("cover TB");
}
}
class A extends T with TA, TB {} // TB
class B extends T with TB, TA {} // TA
void main() {
A a = A();
a.fun();
}
按照我們剛才的理解拆又,我們會(huì)得到如下結(jié)果:
A
cover TA
TA
TB
實(shí)際上儒旬,我們輸出的結(jié)果是:
A
cover TB
TA
TB
回想我們得到的結(jié)論栏账,在mixin繼承鏈中,最后聲明的mixin會(huì)把前面聲明的相同方法覆蓋掉栈源。這時(shí)挡爵,即使我們代碼中調(diào)用了TA的cover方法,實(shí)際上也會(huì)被TB類(lèi)中的cover方法覆蓋掉甚垦。因此最終調(diào)用的還是MB中的方法茶鹃。
四涣雕、總結(jié)
我們大致總結(jié)了mixin的機(jī)制和使用,mixin 是一個(gè)強(qiáng)大的概念闭翩,我們可以跨越類(lèi)的層次結(jié)構(gòu)重用代碼挣郭。在我們看Flutter源碼時(shí),經(jīng)常會(huì)看到使用這個(gè)功能疗韵,我也是在看Flutter代碼時(shí)兑障,看到這個(gè)關(guān)鍵字然后進(jìn)行補(bǔ)腦的。
1.Mixins并不是經(jīng)典意義上獲得多重繼承的方法蕉汪。
2.Mixins是一種抽象和復(fù)用一系列操作和狀態(tài)的方式流译,而且生成多個(gè)中間的mixin類(lèi)。
3.它是線(xiàn)性的者疤,因此與單繼承兼容福澡。
4.Mixins除了繼承Object外,不可以繼承任何其他類(lèi); Mixins不可以定義構(gòu)造方法驹马。