flutter-dart 類的建構函式

黃馬發表於2018-06-21

Dart4Flutter -01 – 變數, 型別和 函式

Dart4Flutter – 02 –控制流 和異常

Dart4Flutter – 03 – 類和泛型

Dart4Flutter – 04 – 非同步和庫

Dart4Flutter -拾遺01 – flutter-dart環境搭建

flutter入門 – 狀態管理

Flutter 入門例項1

flutter-dart 類的建構函式

Constructors 建構函式

通過建立一個和類名相同的函式宣告一個建構函式(除此之外還有命名建構函式)。

建構函式通常用來建立一個類的例項。

class Point {
  num x, y;

  Point(num x, num y) {
    // There`s a better way to do this, stay tuned.
    this.x = x;
    this.y = y;
  }
}
複製程式碼

this關鍵字指向當前例項

將建構函式的引數賦值給例項變數太常見了,dart有一個語法糖使這種情況更加便捷:

class Point {
  num x, y;

  // Syntactic sugar for setting x and y
  // before the constructor body runs.
  Point(this.x, this.y);
}
複製程式碼

Default constructors 預設的建構函式

如果你不宣告建構函式,系統將提供一個預設的建構函式。預設的建構函式沒有引數,而且將呼叫父類的無引數的建構函式。

Constructors aren’t inherited 建構函式不能繼承

子類不能從父類繼承建構函式。宣告無引數的建構函式的子類只有預設的建構函式,即沒有引數、沒有名字(相對於命名建構函式)。

Named constructors 命名建構函式

通過命名建構函式實現一個類可以有多個建構函式,或者提供更有正對性的建構函式:

class Point {
  num x, y;

  Point(this.x, this.y);

  // Named constructor
  Point.origin() {
    x = 0;
    y = 0;
  }
}
複製程式碼

注意:建構函式是不能繼承的,所以子類是不能繼承父類的命名建構函式的。如果你希望使用父類中的建構函式建立子類的例項,你必須在子類中實現父類中的建構函式。

Invoking a non-default superclass constructor 呼叫父類非預設建構函式

預設,子類的建構函式呼叫父類非命名、無參建構函式。父類的建構函式在構函式體之前呼叫。如果有初始化列表,初始化在父類建構函式之前執行。總之,執行順序如下:

  1. 初始化列表
  2. 父類的無參建構函式
  3. 當前類的無參建構函式

如果父類沒有未命名、無參建構函式,那麼你必須手動呼叫父類中的一個建構函式。注意:父類的建構函式呼叫在:之後,建構函式體之前。

在如下的例子中,Employee類的建構函式呼叫他父類Person的命名建構函式。

class Person {
  String firstName;

  Person.fromJson(Map data) {
    print(`in Person`);
  }
}

class Employee extends Person {
  // Person does not have a default constructor;
  // you must call super.fromJson(data).
  Employee.fromJson(Map data) : super.fromJson(data) {
    print(`in Employee`);
  }
}

main() {
  var emp = new Employee.fromJson({});

  // Prints:
  // in Person
  // in Employee
  if (emp is Person) {
    // Type check
    emp.firstName = `Bob`;
  }
  (emp as Person).firstName = `Bob`;
}
複製程式碼

因為父類建構函式的引數在呼叫之前會評估,所以引數可以是表示式,例如一個函式呼叫。

class Employee extends Person {
  Employee() : super.fromJson(getDefaultData());
  // ···
}
複製程式碼

注意:父類建構函式不能使用this.例如,引數可以呼叫靜態方法,但是不能呼叫例項方法。

nitializer list 初始化列表

除了呼叫父類的建構函式,你還可以在執行建構函式體之前初始化例項變數。用逗號分隔每個初始化。

// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map<String, num> json)
    : x = json[`x`],
      y = json[`y`] {
  print(`In Point.fromJson(): ($x, $y)`);
}
複製程式碼

注意:初始化表示式的右邊不能用this.

在開發期間,你可以在出初始化列表中使用assert校驗輸入:

Point.withAssert(this.x, this.y) : assert(x >= 0) {
  print(`In Point.withAssert(): ($x, $y)`);
}
複製程式碼

設定final欄位時,初始化列表還是很方便的。下面你的例子中,在初始化裂變中初始化三個final變數

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);
}
複製程式碼

Redirecting constructors 可重定向的建構函式

有時一個建構函式的目的只是重定向到同類的另一個建構函式。一個可重定向函式的函式體是空的,同時建構函式的呼叫是在冒號之後的。

class Point {
  num x, y;

  // The main constructor for this class.
  Point(this.x, this.y);

  // Delegates to the main constructor.
  Point.alongXAxis(num x) : this(x, 0);
}

複製程式碼

Constant constructors 常量建構函式

如果一個物件是不會改變的,你可以講這些物件建立為編譯時常量。定義cost建構函式,而且要確保所有的常量都是final的。

class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);

  final num x, y;

  const ImmutablePoint(this.x, this.y);
}
複製程式碼

Factory constructors 工廠建構函式

當你需要建構函式不是每次都建立一個新的物件時,使用factory關鍵字。例如工程建構函式返回一個在快取的中的例項或者返回一個子類的例項。

下面的例子說明,從快取中返回例項:

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);
  }
}
複製程式碼

注意:工廠建構函式不能使用this

呼叫工廠建構函式,可以使用new關鍵字

var logger = Logger(`UI`);
logger.log(`Button clicked`);
複製程式碼

相關文章