在創(chuàng)建實(shí)例的時(shí)候最好是使用構(gòu)造函數(shù)而不是靜態(tài)方法。
構(gòu)造函數(shù)通常由 new
或者 const
調(diào)用,其主要目的就是返回該類的一個(gè)實(shí)例(或者至少實(shí)現(xiàn)了其接口)。
在 Dart 中你將不再需要用靜態(tài)方法來創(chuàng)建一個(gè)實(shí)例。已命名的構(gòu)造函數(shù)使你能夠說明對(duì)象是如何構(gòu)建的,并且工場(chǎng)構(gòu)造函數(shù)允許你在合適的情況下構(gòu)建子類以及子接口的實(shí)例。
盡管如此,一些采取一定技巧創(chuàng)建新對(duì)象的方法看起來“并不像構(gòu)造函數(shù)”。比如,盡管 Uri.parse() 是一個(gè)靜態(tài)方法,它卻通過給定的參數(shù)創(chuàng)建了一個(gè) Uri 對(duì)象。相應(yīng)地,實(shí)現(xiàn)了 Builder pattern 的類看起來可能比使用靜態(tài)方法的類要好一些。
不過,在大多數(shù)情況下,即使會(huì)顯得程序冗長(zhǎng)你也應(yīng)該使用構(gòu)造函數(shù)而不是靜態(tài)方法。當(dāng)其他人使用你的類來創(chuàng)建對(duì)象時(shí),他們更希望能夠使用構(gòu)造函數(shù)按照常規(guī)方式來創(chuàng)建實(shí)例。
class Point { // good
num x, y;
Point(this.x, this.y);
Point.polar(num theta, num radius)
: x = radius * math.cos(theta),
y = radius * math.sin(theta);
}
class Point { // bad
num x, y;
Point(this.x, this.y);
static Point polar(num theta, num radius) {
return new Point(radius * math.cos(theta),
radius * math.sin(theta));
}
}
對(duì)于空的構(gòu)造函數(shù)體,用 ;
來代替 {}
。
在 Dart 中,一個(gè)函數(shù)體為空的構(gòu)造函數(shù)可以由分號(hào)來結(jié)尾。這對(duì)于 const 類型的構(gòu)造函數(shù)來說是必要的??紤]到一致性以及簡(jiǎn)潔性,其他構(gòu)造函數(shù)也應(yīng)該做到這點(diǎn)。
class Point { // good
int x, y;
Point(this.x, this.y);
}
class Point { // bad
int x, y;
Point(this.x, this.y) {}
}
請(qǐng)務(wù)必將 super()
的調(diào)用放在構(gòu)造函數(shù)初始化列表的最后。
字段的初始化將會(huì)按照它們?cè)跇?gòu)造函數(shù)初始化列表中出現(xiàn)的順序來進(jìn)行。如果你把對(duì) super()
的調(diào)用放在初始化列表的中間,那么父類中的初始化將會(huì)在子類初始化列表中剩余內(nèi)容之前被初始化。
這并不是說父類構(gòu)造函數(shù)體中的內(nèi)容將會(huì)被執(zhí)行。這往往是在所有的初始化都完成之后才執(zhí)行,而與 super()
的位置無(wú)關(guān)。初始化列表的影響正在逐漸降低,所以 super()
在列表中的位置幾乎沒有什么影響。
最好養(yǎng)成將父類構(gòu)造函數(shù)放在子類構(gòu)造函數(shù)最后的習(xí)慣,這有利于提升代碼的連貫性。并且當(dāng)父類構(gòu)造函數(shù)體運(yùn)行的時(shí)候,其可讀性也會(huì)增加,甚至對(duì)運(yùn)行的效果也會(huì)有提升。
View(Style style, List children) // good
:_children = children,
super(style){
View(Style style, List children) // bad
:super(style),
-children = children {
對(duì)于更改屬性值的操作,請(qǐng)調(diào)用 setter 來執(zhí)行。
如果函數(shù)的名稱是以 set
開頭的,這通常意味著該函數(shù)可能是 setter 函數(shù)。更準(zhǔn)確的說,對(duì)于下面這些情況使用 setter 來代替函數(shù)是比較好的選擇:
foo.bar = value
這樣的表達(dá)式,因?yàn)樗鼈儓?zhí)行很快。rect.width = 3; // good
button.visible = false;
你應(yīng)當(dāng)避免為了“安全”而將字段封裝在 getter 和 setter 中。
在 Java 以及 C# 中,即便我們所需要的操作是直接對(duì)應(yīng)字段的,通常情況下我們還是會(huì)將所有的字段都封裝在 getter 和 setter 中(或者是 C# 的屬性中)。事實(shí)上,如果你需要在成員上做更多操作,你可以不觸及調(diào)用點(diǎn)。這是因?yàn)?,?Java 中調(diào)用一個(gè) setter 函數(shù)和直接操作字段是不同的。而在 C# 中使用屬性和直接操作字段是互不兼容的。
Dart 中并沒有這種限制。字段以及 getter/setter 是完全相同的。你可以先使用類中的字段,然后在不改動(dòng)任何使用了該字段的代碼的情況下將其封裝在 getter 以及 setter 內(nèi)。
class Box { // good
var contents;
}
class Box { // bad
var _contents;
get contents => _contents;
set contents(value) {
_contents = value;
}
}
最好使用 public final 字段來而不是定義一個(gè) private 字段然后為之設(shè)置一個(gè) public setter。
如果你有一個(gè)代碼之外可見的字段并且不會(huì)為它賦值(并且在構(gòu)造函數(shù)之外你不會(huì)更改它),多數(shù)情況下最簡(jiǎn)單的方法就是直接讓它作為 fianl
變量。
class Box { // good
final contents = [];
}
class Box { // bad
var _contents;
get contents => _contents;
}
當(dāng)某個(gè)成員的函數(shù)體返回的是單個(gè)表達(dá)式的時(shí)候,請(qǐng)考慮一下使用 =>
來定義這些成員。
除了函數(shù)表達(dá)式之外,Dart 也允許你使用 =>
來定義類的成員。這對(duì)于定義一些計(jì)算并返回單值的簡(jiǎn)單成員來說是個(gè)好習(xí)慣。
get width => right - left; // good
bool ready(num time) => minTime == null || minTime <= time;
containsValue(String value) => getValues().contains(value);
即便函數(shù)體并不是單行的也可以使用 =>
,但是不過你覺得將當(dāng)行表達(dá)式拆開成多行代碼比較好,那么將整個(gè)函數(shù)體放在花括號(hào)中并顯示聲明 return
看起來會(huì)更好。
你應(yīng)該避免為了使用常規(guī)接口而從函數(shù)中返回 this
。
對(duì)于連續(xù)的函數(shù)調(diào)用,使用函數(shù)級(jí)聯(lián)是種好習(xí)慣。
var buffer = new StringBuffer() // good
..write("one")
..write("two")
..write("three");
var buffer = new StringBuffer(); // bad
buffer
.write("one")
.write("two")
.write("three");
你應(yīng)該避免使用布爾類型的參數(shù),除非它們的含義是非常明顯的。
和其他類型不同,布爾值通常直接使用字面值而不是布爾變量。像數(shù)字我們通常會(huì)將其封裝在命名的常量中,但是在使用的時(shí)候我們通常直接使用true
和 false
。這樣其他人就很難明白你的調(diào)用語(yǔ)句中布爾值究竟意味著什么:
new Task(true); // bad
new Task(false);
new ListBox(false, true, true);
相反,在調(diào)用的時(shí)候,如果你使用命名的參數(shù),命名的構(gòu)造函數(shù)或者是命名后的常量看起來就很舒服。
new Task.oneShot(); // bad
new Task.repeating();
new ListBox(scroll: true, showScrollbars: true);
更多建議: