dart系列之:dart類中的建構函式

flydean發表於2021-11-14

簡介

dart作為一種物件導向的語言,class是必不可少的。dart中所有的class,除了Null都繼承自Object class。 要想使用dart中的類就要構造類的例項,在dart中,一個類的建構函式有兩種方式,一起來看看吧。

傳統的建構函式

和JAVA一樣,dart中可以使用和class名稱相同的函式作為其建構函式,這也是很多程式語言中首先的建構函式的建立方式,我們以Student類為例,來看看dart中的建構函式是怎麼樣的:

class Student {
  int age = 0;
  int id = 0;

  Point(int age, int id) {
    this.age = age;
    this.id = id;
  }
}

上面的this表示的是當前類的例項,對dart來說,this是可以忽略的,但是在上面的例子中,因為類變數的名字和建構函式傳入引數的名字是一樣的,所以需要加上this來進行區分。

上面的程式碼雖然很簡單,但是寫起來還是有太多的內容,下面是dart中的一種簡寫方式:

class Student {
  int age = 0;
  int id = 0;

  Student(this.age, this.id);
}

當然,你也可以不指定建構函式,這樣的話dart會為你建立一個預設的無參的建構函式。

命名建構函式

dart和其他語言不同的地方是,還可以使用命名建構函式。命名建構函式的格式是ClassName.identifier,如下所示:


class Student {
  int age = 0;
  int id = 0;

  Student(this.age, this.id);

    Student.fromJson(Map data) {
    print('in Student');
  }
}

上面的Student.fromJson就是一個命名建構函式。可以使用該建構函式從Map中生成一個Student物件,有點像是java中的工廠方法。

建構函式的執行順序

我們知道,dart中的類是可以繼承的,那麼對於dart中的子類來說,其建構函式的執行順序是怎麼樣的呢?

如果不給dart類指定建構函式,那麼dart會為類自動生成一個無參的建構函式,如果這個類是子類的話,則會自動呼叫父類的無參建構函式。

那麼對應子類的建構函式來說,初始化的時候有三步:

  1. 呼叫初始化列表
  2. 呼叫父類的建構函式
  3. 呼叫自己的建構函式

在步驟2中,如果父類沒有預設的無參建構函式,則需要手動指定具體父類的建構函式。怎麼呼叫呢?可以直接在子類的建構函式後面使用:操作符接父類的建構函式,如下所示:

class Student {
  String? firstName;
  
  Student.fromJson(Map data) {
    print('in Student');
  }
}

class Jone extends Student {
  
  Jone.fromJson(Map data) : super.fromJson(data) {
    print('in Jone');
  }
}

理解了父類的建構函式之後,我們再看一下什麼是初始化列表呢?

初始化列表就是在建構函式執行之前執行的程式碼,和呼叫父類的建構函式一樣,也使用:操作符,如下所示:

Point.fromJson(Map<String, double> json)
    : x = json['x']!,
      y = json['y']! {
  print('In Point.fromJson(): ($x, $y)');
}

重定向建構函式

如果一個建構函式需要呼叫另外一個建構函式,而其本身並不進行任何變動,這可以使用重定向建構函式,重定向建構函式也使用:操作符,後面跟的是另外的建構函式:

class Point {
  double x, y;

  // 主建構函式
  Point(this.x, this.y);

  // 重定向建構函式
  Point.alongXAxis(double x) : this(x, 0);
}

Constant建構函式

如果物件中的屬性在建立之後,是不會變化的,則可以使用Constant建構函式, 也就是在建構函式前面加上const修飾符,初始化的所有屬性都要以final來修飾:

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

  final double x, y;

  const ImmutablePoint(this.x, this.y);
}

工廠建構函式

預設情況下,dart類中的建構函式返回的是該類的新例項,但是我們在實際的應用中可能會對返回的物件做些選擇,比如從快取中返回已經存在的物件,或者返回該類具體的實現子類。

為了實現這樣的功能,dart中專門有一個Factory關鍵字,使用Factory的建構函式叫做工廠建構函式。

class Student {
  final String name;

  static final Map<String, Student> _studentMap =
  <String, Student>{};

  factory Student(String name) {
    return _studentMap.putIfAbsent(
        name, () => Student._newStudent(name));
  }

  factory Student.fromJson(Map<String, Object> json) {
    return Student(json['name'].toString());
  }

  Student._newStudent(this.name);
}
注意,dart中只能有一個未命名的建構函式,對應命名函式來說,名字不能夠重複,否則會報The default constructor is already defined異常。

上面的程式碼中,factory Student是一個未命名建構函式,而factory Student.fromJson則是一個命名建構函式。

所以如果你再給Student加一個未命名建構函式,如下:

Student(this.name);

則會報錯。

那麼問題來了,factory建構函式和普通建構函式到底有什麼區別呢?

他們最大的區別就是普通建構函式是沒有返回值的,而factory建構函式需要一個返回值。

總結

以上就是dart中各種建構函式,和使用過程中需要注意的問題。

本文已收錄於 http://www.flydean.com/06-dart-class/

最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!

相關文章