Dart構(gòu)造函數(shù)有4種格式:
ClassName(...) ? //類名構(gòu)造函數(shù)
Classname.identifier(...) ? //命名構(gòu)造函數(shù)
const ClassName(...)?? //常量構(gòu)造函數(shù)
factroy ClassName(...)?? //工廠構(gòu)造函數(shù)
1. 默認(rèn)構(gòu)造函數(shù)
如果你定義了一個(gè)類,而沒(méi)有定義構(gòu)造函數(shù),那么它將有一個(gè)默認(rèn)的構(gòu)造函數(shù),這個(gè)構(gòu)造函數(shù)沒(méi)有參數(shù)
如果這個(gè)類有父類,那么默認(rèn)構(gòu)造函數(shù),還會(huì)調(diào)用父類的無(wú)參數(shù)構(gòu)造函數(shù)。
2. 類名構(gòu)造函數(shù)
構(gòu)造函數(shù)就是一個(gè)與類同名的函數(shù),構(gòu)造函數(shù)是一個(gè)函數(shù),因此可以參數(shù)化。但是與函數(shù)不同,構(gòu)造函數(shù)不能具有返回類型。
class Point {
? num x, y;
? // 類名構(gòu)造函數(shù)
Point(num x, num y) {
??? // There's abetter way to do this, stay tuned.
??? this.x = x;
??? this.y = y;
? }
}
上例中只有兩個(gè)成員變量,如果有10個(gè),豈不是麻煩死?所以Dart有語(yǔ)法糖如下:
class Point {
? num x, y;
? // Syntacticsugar for setting x and y
? // before theconstructor body runs.
? Point(this.x,this.y);
}
它可以將x,y的賦值變得簡(jiǎn)單一些,就不用寫構(gòu)造函數(shù)的方法體了,記得括號(hào)后用分號(hào)哦。
3. 命名構(gòu)造函數(shù)
在Dart中構(gòu)造函數(shù)的名稱可以是類名 ClassName 或者類名和標(biāo)識(shí)符 ClassName.identifier 。 其中構(gòu)造函數(shù)名稱是“ClassName”的函數(shù)叫“類名構(gòu)造函數(shù)”;構(gòu)造函數(shù)名稱是“ClassName.identifier”的函數(shù)叫“命名構(gòu)造函數(shù)”。
class Point {
? num x, y;
? // 類名構(gòu)造函數(shù)
Point(this.x, this.y);
? // 命名構(gòu)造函數(shù)
? Point.origin() {
??? x= 0;
??? y= 0;
? }
// 命名構(gòu)造函數(shù)
? Point.now(num x, num y)
? {
????? print("這是命名構(gòu)造函數(shù)");
????? this.x = x;
????? this.y = y;
?? }
}
使用命名構(gòu)造函數(shù)可以為類提供多個(gè)構(gòu)造函數(shù),以使類定義多個(gè)構(gòu)造函數(shù)。
請(qǐng)記住,命名構(gòu)造函數(shù)不可繼承,如果子類想要有 和父類一樣的命名構(gòu)造函數(shù),那就寫個(gè)同名的(通常也會(huì)在子類的命名構(gòu)造函數(shù)里,調(diào)用父類的同名命名構(gòu)造函數(shù))
再看一個(gè)實(shí)際例子,加深一下用命名構(gòu)造函數(shù)的好處:橫向擴(kuò)展
RaisedButton 即"漂浮"按鈕,它默認(rèn)帶有陰影和灰色背景。按下后,陰影會(huì)變大,如圖3-10所示:

使用RaisedButton非常簡(jiǎn)單,如:
RaisedButton(?//類名構(gòu)造函數(shù)
? child: Text("normal"),
? onPressed: () {},
);
RaisedButton、FlatButton、OutlineButton都有一個(gè)icon 構(gòu)造函數(shù),通過(guò)它可以輕松創(chuàng)建帶圖標(biāo)的按鈕,如圖3-14所示:

代碼如下:
RaisedButton.icon(?//命名構(gòu)造函數(shù)
? icon:Icon(Icons.send),
? label:Text("發(fā)送"),
? onPressed: _onPressed,
),
OutlineButton.icon(
? icon:Icon(Icons.add),
? label:Text("添加"),
? onPressed:_onPressed,
),
FlatButton.icon(
? icon:Icon(Icons.info),
? label:Text("詳情"),
? onPressed:_onPressed,
),
3.2重定向構(gòu)造函數(shù)(構(gòu)造函數(shù)傳遞)
有時(shí)構(gòu)造函數(shù)的唯一目的是重定向到同一類中的另一個(gè)構(gòu)造函數(shù)。定義構(gòu)造函數(shù)的時(shí)候,除了一個(gè)普通構(gòu)造函數(shù),還可以有若干命名構(gòu)造函數(shù),這些構(gòu)造函數(shù)之間,有時(shí)候會(huì)有一些相同的邏輯,如果分別書寫在各個(gè)構(gòu)造函數(shù)中,會(huì)有些多余,所以構(gòu)造函數(shù)可以傳遞。重定向構(gòu)造函數(shù)沒(méi)有方法體,會(huì)在初始化列表中,構(gòu)造函數(shù)調(diào)用出現(xiàn)在冒號(hào)( :)之后 。 就是在創(chuàng)建類時(shí),定義一個(gè)命名構(gòu)造函數(shù),但是這個(gè)構(gòu)造函式的主體不實(shí)現(xiàn),直接通過(guò)另外一個(gè)構(gòu)造函數(shù)實(shí)現(xiàn)對(duì)外界傳入的參數(shù)接收并賦值給內(nèi)部的變量。
class Point {
? num x, y;
? // The main constructor for this class.
? Point(this.x, this.y);
? // Delegates to the main constructor.
? Point.alongXAxis(Map<String, num> json)
??? :x = json['x'],
????? y= json['y'] {
? print('In Point.fromJson(): ($x, $y)');
}? //初始化列表就是構(gòu)造函數(shù)名的冒號(hào)后面,打括號(hào)前面的部分。
}
初始化列表的執(zhí)行順序,在整個(gè)構(gòu)造函數(shù)的最前面,它除了可以調(diào)用父類的構(gòu)造函數(shù),還可以在構(gòu)造函數(shù)方法體之前,初始化一些成員變量。
import 'dart:math';
class Point {
? final num x;
? final num y;
? final num distanceFromOrigin;
? Point(x, y)
????? :x = x,
??????? y= y,
??????? distanceFromOrigin= sqrt(x * x + y * y);
}
main() {
? var p = new Point(2, 3);
? print(p.distanceFromOrigin);
}
再看計(jì)數(shù)器示例的代碼,是不是有感覺了:語(yǔ)法糖和初始化列表都出現(xiàn)了
class MyHomePage extends StatefulWidget {
? MyHomePage({Key key
, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
? // that it has a State object (defined below) that contains fields that affect
? // how it looks.
? // This class is the configuration for the state. It holds the values (in this
? // case the title) provided by the parent (in this case the App widget) and
? // used by the build method of the State. Fields in a Widget subclass are
? // always marked "final".
final String title;
4. 常量構(gòu)造函數(shù)
class ImmutablePoint {
? static final ImmutablePoint origin =
????? const ImmutablePoint(0, 0);
? final num x, y;
? const ImmutablePoint(this.x, this.y);
}
如果你的類,創(chuàng)建的對(duì)象永遠(yuǎn)不會(huì)改變,你可以在編譯期就創(chuàng)建這個(gè)常量實(shí)例,并且定義一個(gè)常量構(gòu)造函數(shù),并且確保所有的成員變量都是final的。
5. 工廠構(gòu)造函數(shù)
有時(shí)候可能有一種需求,并不需要每次都創(chuàng)建新的類實(shí)例,而是每一種情況,只需要一個(gè)實(shí)例:
class Logger {
? final String name;
? bool mute= false;
? // _cache is library-private, thanks to the _ in front of its name.
? static final Map<String, Logger> _cache =
????? <String, Logger>{};
? factory Logger(String name) {
??? if (_cache.containsKey(name)) {
?????return _cache[name];
??? } else {
????? final logger = Logger._internal(name);
????? _cache[name] = logger;
????? return logger;
??? }
? }
? Logger._internal(this.name);
? void log(String msg) {
??? if (!mute) print(msg);
? }
}
main() {
??? var logger = Logger('UI');
??? logger.log('Button clicked');
}
工廠構(gòu)造函數(shù),沒(méi)有權(quán)利訪問(wèn)this
上例的意思是,類中又一個(gè)靜態(tài)緩存_cache保存著一些Logger類實(shí)例,創(chuàng)建實(shí)例時(shí),給工廠構(gòu)造函數(shù)傳遞的name,如果在緩存中已經(jīng)存在,就用緩存中現(xiàn)成的實(shí)例,如果沒(méi)有,就新建一個(gè)實(shí)例,并且也放到緩存中。
如此這般,我們可以創(chuàng)建名字為UI / SYS / API 等的實(shí)例,然后在debug的時(shí)候,如果設(shè)置名字為UI的Logger實(shí)例的mute為true,就不會(huì)打印UI相關(guān)的log,而不影響其它兩個(gè)名字的log。是不是很方便呢?
尾記:
學(xué)習(xí)Dart語(yǔ)法時(shí)建議結(jié)合實(shí)際例子中的用法去理解,語(yǔ)法特性也是為實(shí)際場(chǎng)景服務(wù)的,掌握背后的意義,才能真正掌握一門工具,用好一門語(yǔ)言。