【问题标题】:Flutter: When should the factory constructor be used?Flutter:什么时候应该使用工厂构造函数?
【发布时间】:2021-02-18 02:48:04
【问题描述】:

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类的工厂构造函数并不总是创建一个新的实例,所以 我可以理解添加工厂关键字,

这个 Complete 示例的 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');
  }
}

如您所见,即使我尝试仅使用普通构造函数,它似乎也可以正常工作。

准备和使用工厂构造函数有什么好处吗?

或者在这种情况下不使用工厂构造函数有什么问题吗?

我不确定什么时候首先使用工厂构造函数, 有明确的定义吗?

【问题讨论】:

  • 我看不出Album.fromJson 需要成为factory 构造函数的任何原因。它可以用redirecting constructor 来实现。该示例可能使用factory 与使用json_serializablebuilt_value.fromJson 构造函数保持一致(或出于习惯),并且必须使用factory 构造函数。

标签: flutter dart


【解决方案1】:

在深入了解 factory 作为 Flutter 中的关键字之前,您可以先了解一下作为设计模式的 Factory 以了解全貌。

使用工厂设计模式的主要好处

也就是说,工厂方法设计模式为负责创建对象的类定义了一个接口,因此将实例化推迟到实现该接口的特定类。这解决了直接在使用它们的类中创建对象的问题。 此外,它通过子类化实现了编译时的灵活性。当在类中创建对象时,它非常不灵活,因为您不能独立于类更改对象的实例化——类被提交给特定对象。通过实现该模式,可以编写子类来重新定义对象的创建方式。

欲了解更多信息,请参阅here

正如docs所指

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

所以这一切都是为了向外界隐藏创建逻辑。

当然你也可以这样做

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

但是,假设您在许多不同的组件或类中这样做,那么每当您更改创建 Album 对象背后的逻辑时,您将需要在所有地方进行更改。

另一方面,使用Album 类的类只关心拥有AlbumObject,而不关心它是如何被实例化的,所以如果你把拥有一个实例的逻辑放在类本身,您将进入所谓的 spaghetti 代码

【讨论】:

    【解决方案2】:

    您可以使用工厂来测试例如 som 请求返回的 json 数据是否为空,因此您可以通过使用工厂命名的构造函数直接返回空,例如看看这个

    //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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-29
      • 1970-01-01
      • 1970-01-01
      • 2021-01-27
      相关资源
      最近更新 更多