簡體   English   中英

dart 工廠構造器標識符的優點

[英]dart advantage of a factory constructor identifier

我一直在為我的 Flutter 應用程序調查 JSON 解析,並且對我無法解決的工廠構造函數有疑問。 我試圖了解使用工廠構造函數與普通構造函數的優勢。 例如,我看到很多 JSON 解析示例創建 model class 和 Z0ECD11C41D7A287A201

class Student{
  String studentId;
  String studentName;
  int studentScores;

  Student({
    this.studentId,
    this.studentName,
    this.studentScores
  });

  factory Student.fromJson(Map<String, dynamic> parsedJson){
    return Student(
      studentId: parsedJson['id'],
      studentName : parsedJson['name'],
      studentScores : parsedJson ['score']
    );
  }
}

我還看到了相同數量的不將構造函數聲明為工廠的示例。 兩種類型的 classname.fromJSON 構造函數都從 JSON 數據創建了 object ,因此將構造函數聲明為工廠或在此處使用工廠是多余的嗎?

普通構造函數總是返回當前類的一個新實例(除非構造函數拋出異常)。

工廠構造函數與靜態方法非常相似,不同之處在於它

  • 只能返回當前類或其子類之一的實例
  • 可以用new調用,但現在不太相關,因為new成為可選的。
  • 沒有初始化列表(沒有: super()

所以可以使用工廠構造函數

  • 創建子類的實例(例如取決於傳遞的參數
  • 返回緩存實例而不是新實例
  • 准備計算值以將它們作為參數轉發給普通構造函數,以便可以使用它們初始化最終字段。 這通常用於解決在普通構造函數的初始化列表中可以完成的操作的限制(如錯誤處理)。

在您的示例中,此代碼

  studentId: parsedJson['id'],
  studentName : parsedJson['name'],
  studentScores : parsedJson ['score']

可以移動到普通構造函數的主體,因為不需要初始化final字段。

工廠構造函數與普通構造函數

  • 工廠構造函數調用另一個構造函數。
  • 由於工廠構造函數不直接創建新實例,因此它不能使用構造函數初始值設定項列表。
  • 一個普通的構造函數總是返回一個類的新實例。 允許工廠構造函數返回現有實例、派生類的實例或null (然而, 有些人不喜歡返回null從工廠構造函數。需要注意的是返回null從一個工廠的構造是不允許用空安全。)
  • 由於上述原因,擴展類不能調用工廠構造函數作為超類構造函數。 因此,僅提供factory構造函數的類不能使用派生類進行擴展。

工廠構造函數與靜態方法

  • 工廠構造函數可以是類的未命名的默認構造函數。
  • 工廠構造函數可以與new一起使用。 (但現在不鼓勵使用new 。)
  • 靜態方法可用於創建撕裂(即,它們可用作回調)但構造函數目前不能
  • 靜態方法可以是async (工廠構造函數必須返回其類的類型,因此它不能返回Future 。)
  • 工廠構造函數可以聲明為const
  • 在空安全 Dart 中,工廠構造函數不能返回可空類型。
  • 在生成的 dartdoc 文檔中,工廠構造函數顯然將列在“構造函數”部分(位於頂部的顯眼位置)中,而靜態方法將在“靜態方法”部分(當前隱藏在底部)中。

在我注意到並想知道同樣的問題之后,鑒於我認為其他答案實際上並沒有回答這個問題(“我一直在研究 JSON 解析 [...] 我試圖了解使用工廠構造函數與普通構造函數相對”),這里是我的嘗試:

在解析 json 時,使用工廠構造函數而不是普通構造函數沒有任何我能看到或理解的優勢或差異。 我對所有類型的參數都試過,兩者都可以正常工作。 我最終決定采用工廠構造函數,因為代碼編寫方式方便且可讀性強,但這是一個選擇問題,兩者在所有情況下都可以正常工作。

工廠構造函數的用途之一是,我們可以決定在運行時創建哪個實例並將所有邏輯移動到父級的工廠構造函數

假設您有 1 個父類和 2 個子類

class GolderRetriever extends Dog{
   GolderRetriever(String name):super(name);
}
class Labrador extends Dog{
  Labrador(String name):super(name);
}

然后我們有父類

class Dog{
  final String name;
  Dog(this.name);
  
  
  factory Dog.createInstance({required String name,DogType type=DogType.UNKNOWN}){
    
    if(type==DogType.GOLDEN_RETRIEVER){
      return GolderRetriever(name);
    }
    else if(type==DogType.DALMATION){
      return Labrador(name);
    }else{
    return Dog(name);
    }
  }
}

而且我有 enum DogType

enum DogType{
  GOLDEN_RETRIEVER,DALMATION,UNKNOWN
}

然后在主方法中,您只需將要創建的子類實例委托給父 Dog 類

main() {
     
  Dog myDog = Dog.createInstance(name:"Rocky",type:DogType.DALMATION);
  Dog myNeighboursDog =  Dog.createInstance(name:"Tommy",type:DogType.GOLDEN_RETRIEVER);
  Dog strayDog = Dog.createInstance(name:"jimmy");
}

您不能使用命名構造函數執行此操作,因為您只能創建該類(Dog 類)的實例,而不是其子類型。

現在,創建哪個實例的責任委托給父類。 這可以刪除很多 if-else 樣板代碼。 當您想更改邏輯時,只需在 Animal 類中更改即可。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM