dart工厂构造函数标识符的优势

时间:2018-09-12 16:00:42

标签: dart flutter

我一直在研究我的Flutter应用程序的JSON解析,并且对我无法解决的工厂构造函数有疑问。我试图了解使用工厂构造函数与普通构造函数相比的优势。例如,我看到很多JSON解析示例,这些示例使用JSON构造函数创建模型类,如下所示:

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数据创建对象,因此将构造函数声明为工厂还是在这里使用工厂是多余的?

4 个答案:

答案 0 :(得分:9)

普通构造函数总是返回当前类的新实例(除非构造函数抛出异常)。

工厂构造函数与静态方法非常相似,不同之处在于

  • 只能返回当前类或其子类之一的实例
  • 可以使用new调用
  • ,但是由于new成为可选参数,因此现在不再那么重要了。
  • 没有初始化程序列表(没有: super()

因此可以使用工厂构造函数

  • 创建子类的实例(例如,取决于传递的参数
  • 返回一个缓存实例而不是一个新实例
  • 准备计算的值以将它们作为参数转发给常规构造函数,以便最终字段可以用它们初始化。这通常用于解决普通构造函数的初始化列表中可以完成的操作的局限性(例如错误处理)。

在您的示例中,此代码

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

由于无需初始化final字段,因此可以移动到普通构造函数的正文中。

答案 1 :(得分:2)

工厂构造函数与普通构造函数

  • 工厂构造函数调用另一个构造函数。
  • 由于工厂构造函数不会直接创建新实例,因此无法使用构造函数初始化列表。
  • 普通的构造函数总是返回该类的新实例。允许工厂构造函数返回现有实例,派生类的实例或null。 (不过,some people dislike returning null from a factory constructor。)

工厂构造函数与静态方法

  • 工厂构造函数可能是类的未命名默认构造函数。
  • 工厂构造函数可以与new一起使用。 (但是using new is now discouraged。)
  • 静态方法可用于创建剥离(即,它们可用作回调),但constructors currently can't
  • 静态方法可以为async。 (工厂构造函数必须返回其类的类型,因此它不能返回Future。)

答案 2 :(得分:1)

在我注意到并想知道同样的问题之后,并且鉴于我不认为其他答案实际上回答了这个问题(“我一直在研究JSON解析[...],我试图了解其优势使用工厂构造函数与普通构造函数的对比”),这是我的尝试:

在解析json时,使用工厂构造函数而不是普通构造函数没有任何优势或区别。我尝试了两种,并且都可以使用所有类型的参数。由于代码编写的便利性和可读性,我最终决定采用工厂构造函数,但这是一个选择问题,两者在所有情况下都可以正常工作。

答案 3 :(得分:0)

工厂构造函数的用途之一是,我们可以在运行时决定创建哪个实例并将所有逻辑移至父级的工厂构造函数

假设您有 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 类中更改即可。