Dart 成員

2018-09-28 18:38 更新

成員

在創(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ù)是比較好的選擇:

  • 采用單個(gè)參數(shù)。
  • 改變了對(duì)象中的某個(gè)狀態(tài)。
  • 有一個(gè)相應(yīng)的 getter。對(duì)于使用者來說,有一些可以修改但是卻無(wú)法看見的狀態(tài)是有些奇怪的。(該準(zhǔn)則反過來則是不對(duì)的,設(shè)置了 getter 而不為它定義 setter 也是可以的)
  • 是冪等的。使用同一個(gè)值來調(diào)用兩次 setter 時(shí),第二次調(diào)用應(yīng)當(dāng)不含有其他操作。
  • 為了快速運(yùn)行。使用者們期待像 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í)候我們通常直接使用truefalse。這樣其他人就很難明白你的調(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);
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)