Flutter:何时应使用工厂构造函数?

7

https://flutter.dev/docs/cookbook/networking/fetch-data

在上述页面的最后一个“完整示例”中,
class Album {
  final int userId;
  final int id;
  final String title;

  Album({this.userId, this.id, this.title});

  factory Album.fromJson(Map<String, dynamic> json) {
    return Album(
      userId: json['userId'],
      id: json['id'],
      title: json['title'],
    );
  }
}

这是一个Album类,用于接收请求中收到的JSON字符串,并在应用程序中处理它, 构造函数除了普通构造函数外还提供了工厂构造函数。

关于工厂构造函数, https://dart.dev/guides/language/language-tour#constructors

我已经阅读了上面页面的工厂构造函数部分。

在示例中Logger类的工厂构造函数并不总是创建新实例,因此 我可以理解添加工厂关键字,

即使在这个完整的示例中的Album类中也需要使用工厂构造函数吗?

在Album类的情况下,由于在工厂构造函数中使用了普通构造函数, 我觉得这个工厂构造函数(Album.fromJson)总是会创建一个新的实例。 实际上

Future<Album> fetchAlbum() async {
  final response =
  await http.get('https://jsonplaceholder.typicode.com/albums/16');

  if (response.statusCode == 200) {
    // If the server did return a 200 OK response,
    // then parse the JSON.
    var temp=json.decode(response.body);
    return Album(userId:temp['userId'],id:temp['id'],title:temp['title']);
  } else {
    // If the server did not return a 200 OK response,
    // then throw an exception.
    throw Exception('Failed to load album');
  }
}

您可以看到,即使我只使用普通构造函数,似乎也没有任何问题。

准备并使用工厂构造函数有什么优势吗?

在这种情况下不使用工厂构造函数是否存在问题?

我不确定何时首先使用工厂构造函数,是否有明确的定义?


2
我没有看到 Album.fromJson 必须是一个 factory 构造函数的任何理由。它可以使用重定向构造函数来实现。那个例子可能为了与使用 json_serializablebuilt_value.fromJson 构造函数保持一致(或出于习惯),因为这些必须使用 factory 构造函数。 - jamesdlin
2个回答

6

在深入探讨flutter中关键字factory之前,您可能需要了解工厂设计模式的Factory以全面了解。

使用工厂设计模式的主要优点是:

即工厂方法设计模式为负责创建对象的类定义了一个接口,从而将实例化延迟到实现此接口的特定类。这解决了在使用它们的类中直接创建对象的问题。此外,通过子类编程使编译时更加灵活。当对象在类内部创建时,非常不灵活,因为您无法独立于类更改对象的实例化 —— 类已经被赋予了特定对象。通过实现该模式,可以编写子类来重新定义对象的创建方式。

详细信息请参见这里

并且如文档所述:

当实现不总是创建其类的新实例的构造函数时,请使用工厂关键字。例如,工厂构造函数可以从缓存返回实例,或者可以返回子类型的实例。工厂构造函数的另一个用例是使用无法在初始化程序列表中处理的逻辑来初始化最终变量。

因此,一切都是关于隐藏创建逻辑,不让外部世界知道。

当然,您也可以执行以下操作:

return Album(userId:temp['userId'],id:temp['id'],title:temp['title']);

但如果你在许多不同的组件或类中这样做,每当更改创建Album对象的逻辑时,您都需要在所有位置上进行更改。

另一方面,使用Album类的类仅关心拥有AlbumObject,他们并不在意它是如何被实例化的,因此,如果将拥有实例的逻辑放在类本身之外,就会陷入所谓的“意大利面条”代码。


3

你可以使用工厂方法测试例如某个请求返回的json数据是否为空,因此可以通过使用名为构造函数的工厂来直接返回null。例如,请看下面的代码:

//class for Product, Brand, Model
class PBM {
  static const String pbmCollectionName = 'productsBrandsModels';
  static const String pbmIdField = 'pbmId';
  static const String pbmNameField = 'pbmName';
  static const String parentIdField = 'parentId';
  static const String iconUrlField = 'iconUrl';
  //general
  final String pbmId;
  final String pbmName;
  final String parentId;

  //icon
  final String iconUrl;

  PBM({
    this.pbmId,
    this.pbmName,
    this.parentId,
    this.iconUrl,
  });

  Map<String, dynamic> toMap() {
    return {
      'pbmId': pbmId,
      'pbmName': pbmName,
      'parentId': parentId,
      'iconUrl': iconUrl,
    };
  } //end of toMap method

  factory PBM.fromFirestore(Map<String, dynamic> firestore) {
    //here the benefit of factory comes into play: it will return a null 
    //otherwise it gonna create the object
    if (firestore == null) return null;
    return PBM(
      pbmId: firestore['pbmId'],
      pbmName: firestore['pbmName'],
      parentId: firestore['parentId'],
      iconUrl: firestore['iconUrl'],
    );
  } //end of PBM.fromFirestore named constructor
} //end of PBM class

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接