前言:
最近看了很多關(guān)于標(biāo)題的文章访娶,忙里偷閑總結(jié)一下自己的理解商虐,這篇文章的總結(jié)不會很全面的解釋各個名詞的概念,而是針對我個人覺著大家容易遺漏混淆的點崖疤,或者比較重要的點的一個總結(jié)秘车。如果對概念都不清晰的朋友可先自行百度了解。
ps:有不對的地方還請大家指正劫哼,謝謝叮趴。
ps:今天又看到一篇關(guān)于這塊內(nèi)容不錯的文章- http://www.reibang.com/p/863c531380cd
-
abstract 抽象類
1、抽象類不能被實例化权烧,只有繼承它的子類可以眯亦。
2、抽象類中一般我們把沒有方法體的方法稱為抽象方法般码。
3妻率、子類繼承抽象類必須實現(xiàn)它的抽象方法。
4板祝、如果把抽象類當(dāng)做接口實現(xiàn)的話必須得實現(xiàn)抽象類里面定義的所有屬性和方法宫静。
-
mixins 混入
1、mixin用于修飾類券时,和abstract類似囊嘉,該類可以擁有成員變量、普通方法革为、抽象方法扭粱,但是不可以實例化。
2震檩、mixin一般用于描述一種具有某種功能的組塊琢蛤,而某一對象可以擁有多個不同功能的組塊蜓堕。
- mixin:定義了組塊。
- on:限定了使用mixin組塊的宿主必須要繼承于某個特定的類博其;在mixin中可以訪問到該特定類的成員和方法套才。
- with:負(fù)責(zé)組合組塊,而with后面跟的類并不一定需要是mixin的慕淡,abstract class和普通類都是可以的背伴,這一點需要注意
混入的一些基本概念與作用的理解可以參考https://blog.csdn.net/HuberCui/article/details/93468810
下面用一些實際的例子來加深我們的理解:
在我們開發(fā)多屏app的時候,我們更傾向于復(fù)用一些類的代碼去完成一些功能峰髓,讓代碼能夠“高復(fù)用”傻寂,比如:全局錯誤提示、頁面的公共視圖部分的復(fù)用携兵、響應(yīng)式編程(Bloc)里面的依賴邏輯等疾掰。使用抽象類abstract基本上就能完成這些功能,但是問題來了徐紧,如果頁面上的公共部分我不想用到所有頁面静檬,只想在特定的頁面上用,那該怎么辦呢? 比如AppBar, 部分頁面不需要公共的并级,而需要自定義拂檩,因為一個class類只能是一個類的子類,而我們需要更靈活的類的組合嘲碧,這就是我們?yōu)槭裁葱枰猰ixin广恢。
ps:本段轉(zhuǎn)自http://www.reibang.com/p/7e14ed414dce,這是我覺得很好的一篇關(guān)于mixins實踐的文章呀潭。
1钉迷、flutter中的繼承是單繼承,使用mixins相當(dāng)于變相的實現(xiàn)了多繼承钠署。
2糠聪、由于mixins通過代碼更好理解它的含義與用法,上代碼谐鼎!
mixin到底是怎么用的舰蟆?讓我們先舉一個例子,新建一個abstract class Person
abstract class Person {
void think() {
print("Hmm, I wonder what I can do today");
}
}
我們可以用extend關(guān)鍵字把這個類作為父類來使用狸棍,比如:
class Mike extends Person {} //由于person類里并不是抽象方法稽荧,我們可以不實現(xiàn)或者重寫
void main() {
var mike = Mike();
mike.think(); // prints: "Hmm, I wonder what I can do today"
}
但是我們要這么給Mike添加一些其他“新功能”呢粒蜈?比如Mike是一位 coder 郎仆,他有coder的一些特性炕婶,但不是所有人都有,該怎么辦呢唐片? mixin就能解決這個問題丙猬。
首先涨颜,我們需要創(chuàng)建一個mixin類并添加一我們需要的新的方法:
mixin Coder {
void code() {
print("Coding intensifies");
}
}
使用關(guān)鍵字with,我們能將這個“新功能”添加給Mike:
class Mike extends Person with Coder {}
并且,與父類一樣茧球,我們可以調(diào)用在Coder中創(chuàng)建的所有函數(shù):
void main() {
var mike = Mike();
mike.code(); // prints: "Coding intensifies"
}
現(xiàn)在庭瑰,每一個使用 mixin coder的類都擁有coder的方法,然而這帶來了一個問題:這意味著抢埋,如果我們有一個帶有子級Squirrel的父類Animal弹灭,那么我們也可以擁有一個可以code()方法的Squirrel!為了防止這種情況揪垄,我們可以使用關(guān)鍵字on將mixin的使用“鎖定”到一個類以及從該類繼承的所有類:
mixin Coder on Person{
void code() {
print("Coding intensifies");
}
}
這相當(dāng)于為我們提供了一個強大的工具:現(xiàn)在我們可以覆蓋重寫在Person類中設(shè)置的方法用來添加或擴展其功能穷吮。
mixin Coder on Person{
//...
@override
void think() {
super.think();
print("I'm going to code today!");
}
}
調(diào)用super.think()可確保我們?nèi)匀豢梢哉{(diào)用Person中定義的代碼,上面的代碼擴展了Mike類的think()方法將會輸出:
Hmm, I wonder what I can do today
I'm going to code today!
- 接下來用一個開發(fā)中可能會經(jīng)常遇到的情景來加深我們的理解
mixins 與 基礎(chǔ)類:一個實際的常用例子
先試著想一下這種情況我們在flutter app中應(yīng)該怎么做:
在app中我們有兩個頁面是這樣的:
我們的app有幾個屏幕如上面顯示的那樣福侈。我們想共用每個屏幕的AppBar和background酒来,我們可以使用mixin解決問題卢未。
在這種情況下肪凛,我們都定義了屏幕標(biāo)題,我們將創(chuàng)建一個基類辽社,該基類具有一種提供屏幕名稱的方法伟墙,該基類稱為BasePage。我們也將僅在StatefulWidgets中應(yīng)用mixins滴铅,因為我們的類將維護并更改其狀態(tài)戳葵。這樣,我們創(chuàng)建了兩個用于頁面的類:BasePage和BaseState <BasePage>分別繼承StatefulWidget和State <StatefulWidget>汉匙。
abstract class BasePage extends StatefulWidget {
BasePage({Key key}) : super(key: key);
}
// TODO: Page為命名泛型 繼承 BasePage, BaseState作為抽象基類拱烁,也會被子類繼承,所以傳入泛型限制參數(shù)類型
abstract class BaseState<Page extends BasePage> extends State<Page> {
String screenName();
}
我們現(xiàn)在創(chuàng)建一個自定義mixin BasicPageMixin噩翠,在其中定義頁面的背景和標(biāo)題名稱戏自。
// TODO: BasicPage 是一個mixin,作用于BaseState和其基類, 抽取渲染頁面公共部分
mixin BasicPage<Page extends BasePage> on BaseState<Page> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(screenName()),
),
body: Container(
child: body(),
color: Colors.amber,
));
}
Widget body();
}
由于body()方法沒有實例,因此使用此mixin的每個類都必須實現(xiàn)它伤锚,以確保我們不會忘記在頁面中添加body()擅笔。
在屏幕上面我們看到了FloatingActionButton,但是我們不是每個屏幕都需要展示它屯援,該怎么辦呢猛们?我們可以聲明一個新方法fab(),默認(rèn)的渲染輸出一個空的Container狞洋。如果繼承的子類需要它弯淘,那么子類可以通過@override重寫fab()來添加一個FloatingActionButton。
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(screenName()),
),
body: Container(
child: body(),
color: Colors.amber,
));
floatingActionButton: fab(),
}
// NOTE: 這里沒有在基類中初始化是因為渲染wedget 盡量寫在子組件state中, 更好的狀態(tài)管理,更好的性能
// TODO: body()子類必須實現(xiàn)
Widget body();
// TODO: fab()子類可選實現(xiàn)
Widget fab() => Container();
}
我們的mixin 已經(jīng)創(chuàng)建好了吉懊, 我們來通過它新建一個頁面:
class MyMixinHomePage extends BasePage {
MyMixinHomePage({Key key}) : super(key: key);
@override
_MyMixinHomePageState createState() => _MyMixinHomePageState();
}
class _MyMixinHomePageState extends BaseState<MyMixinHomePage> with BasicPage{
@override
String screenName() => "Home";
@override
Widget body() {
return Center(child: Text("This is a basic usage of a mixin"));
}
}
有了這個耳胎,我們現(xiàn)在只需要聲明一個body()和一個可能在屏幕中使用的fab()小部件惯吕,從而節(jié)省了幾十行代碼。very nice !
-
implements 接口實現(xiàn)
1怕午、implements與extends最大的不同就是允許后面接上多個普通或者抽象類废登,當(dāng)我們使用B implement A修飾時,那么A中的所有的屬性和方法都要在A中實現(xiàn)郁惜,無論它原來是抽象方法還是普通方法堡距。
2、如果我們只想要A中的接口定義兆蕉,而不想要它的實現(xiàn)羽戒,那么就試用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();
}
輸出結(jié)果:
log#base
log