Dart 學習筆記-類、枚舉、方法

參考:https://www.dartcn.com/guides/language/language-tour#%E7%B1%BB

Dart 是一種基於類和 mixin 繼承機制的面向對象的語言。 每個對象都是一個類的實例,所有的類都繼承於 Object

基於 Mixin 繼承 意味着每個類(除 Object 外) 都只有一個超類, 一個類中的代碼可以在其他多個繼承類中重複使用。

使用類的成員變量

對象的由函數和數據(即方法和實例變量)組成。 方法的調用要通過對象來完成: 調用的方法可以訪問其對象的其他函數和數據。

使用 (.) 來引用實例對象的變量和方法:

var p = Point(2, 2);

// 爲實例的變量 y 設置值。
p.y = 3;

使用 ?. 來代替 . , 可以避免因爲左邊對象可能爲 null , 導致的異常:

var p = Point(2, 2);

// 如果 p 爲 non-null,設置它變量 y 的值爲 4。
p?.y = 4;

使用構造函數

通過 構造函數 創建對象。 構造函數的名字可以是 ClassName 或者 ClassName.identifier。例如, 以下代碼使用 PointPoint.fromJson() 構造函數創建 Point 對象:

var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});

獲取對象的類型

使用對象的runtimeType 屬性, 可以在運行時獲取對象的類型, runtimeType 屬性回返回一個 Type 對象。

print('The type of a is ${a.runtimeType}');

構造函數

通過創建一個與其類同名的函數來聲明構造函數

class Point {
  num x, y;

  Point(num x, num y) {
    this.x = x;
    this.y = y;
  }
}

通常模式下,會將構造函數傳入的參數的值賦值給對應的實例變量, Dart 自身的語法糖精簡了這些代碼:

class Point {
  num x, y;

  // 在構造函數體執行前,
  // 語法糖已經設置了變量 x 和 y。
  Point(this.x, this.y);
}

在沒有聲明構造函數的情況下, Dart 會提供一個默認的構造函數。 默認構造函數沒有參數並會調用父類的無參構造函數。

子類不會繼承父類的構造函數。 子類不聲明構造函數,那麼它就只有默認構造函數 (匿名,沒有參數) 。

重定向構造函數

有時構造函數的唯一目的是重定向到同一個類中的另一個構造函數。 重定向構造函數的函數體爲空, 構造函數的調用在冒號(:)之後。(類似於Android中自定義 View需要實現多個構造函數時調用最終的構造函數)

class Point {
  num x, y;

  // 類的主構造函數。
  Point(this.x, this.y);

  // 指向主構造函數
  Point.alongXAxis(num x) : this(x, 0);
}

工廠構造函數

當執行構造函數並不總是創建這個類的一個新實例時,則使用 factory 關鍵字。 例如,一個工廠構造函數可能會返回一個 cache 中的實例, 或者可能返回一個子類的實例。
(類似於Android中單例模式)

以下示例演示了從緩存中返回對象的工廠構造函數:

class Logger {
  final String name;
  bool mute = false;

  // 從命名的 _ 可以知,
  // _cache 是私有屬性。
  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。

工廠構造函的調用方式與其他構造函數一樣:

var logger = Logger('UI');
logger.log('Button clicked');

方法

方法是爲對象提供行爲的函數。

實例方法

對象的實例方法可以訪問 this 和實例變量。 以下示例中的 distanceTo() 方法就是實例方法:

import 'dart:math';

class Point {
  num x, y;

  Point(this.x, this.y);

  num distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
  }
}

抽象方法

只定義接口不進行實現,而是留給其他類去實現。 抽象方法只存在於 抽象類 中。
定義一個抽象函數,使用分號(;)來代替函數體:

abstract class Doer {
  // 定義實例變量和方法 ...
  void doSomething(); // 定義一個抽象方法。
}

class EffectiveDoer extends Doer {
	@override
  void doSomething() {
    print("123");
    // 提供方法實現,所以這裏的方法就不是抽象方法了...
  }
}

void main() {
  var eff = EffectiveDoer();
  eff.doSomething();
}

輸出:
123

枚舉類型

枚舉類型也稱爲enumerations 或 enums , 是一種特殊的類,用於表示數量固定的常量值。
使用 enum關鍵字定義一個枚舉類型:

enum Color { red, green, blue }

枚舉中的每個值都有一個index getter 方法, 該方法返回值所在枚舉類型定義中的位置(從 0 開始)。
例如,第一個枚舉值的索引是 0 , 第二個枚舉值的索引是 1。

assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);

使用枚舉的values常量, 獲取所有枚舉值列表(list )。

List<Color> colors = Color.values;
assert(colors[2] == Color.blue);

爲類添加功能: Mixin

Mixin 是複用類代碼的一種途徑, 複用的類可以在不同層級,之間可以不存在繼承關係。

通過創建一個繼承自 Object 且沒有構造函數的類,來 實現 一個Mixin 。 如果 Mixin不希望作爲常規類被使用,使用關鍵字 mixin 替換 class 。 例如:

mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}

通過 with 後面跟一個或多個混入的名稱,來 使用 Mixin , 下面的示例演示了兩個使用 Mixin 的類:

class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person
    with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    // Musical 類中的變量
    canConduct = true;
  }
}

指定只有某些類型可以使用的 Mixin -比如, Mixin 可以調用 Mixin 自身沒有定義的方法 - 使用 on 來指定可以使用Mixin的父類類型:

mixin MusicalPerformer on Musician {
  // ···
}

mixin 詳解可查看 Dart之Mixin詳解

類變量和方法

使用 static 關鍵字實現類範圍的變量和方法。

靜態變量

Dart中靜態變量只到它們被使用的時候纔會初始化。

Java中靜態變量是隨着類的加載而加載的,所以當類加載進內存的時候,靜態變量就已經伴隨着類的加載而初始化進內存了,並且靜態變量只在類加載時加載一次,存放在方法區中的靜態區中。

class Queue {
  static const initialCapacity = 16;
  // ···
}

void main() {
  assert(Queue.initialCapacity == 16);
}

靜態方法

靜態方法(類方法)不能在實例上使用,因此它們不能訪問 this 。 例如:

import 'dart:math';

class Point {
  num x, y;
  Point(this.x, this.y);

  static num distanceBetween(Point a, Point b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
  }
}

void main() {
  var a = Point(2, 2);
  var b = Point(4, 4);
  var distance = Point.distanceBetween(a, b);
  assert(2.8 < distance && distance < 2.9);
  print(distance);
}

輸出:
2.8284271247461903
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章