7

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

In the last 'complete example' of the above page,

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'],
    );
  }
}

It is an Album class to receive the JSON string received in the request and handle it in the application, The constructor provides a factory constructor in addition to the normal constructor.

About the factory constructor, https://dart.dev/guides/language/language-tour#constructors

I have read the Factory constructors section of the above page.

The factory constructor of the Logger class in the sample does not always create a new instance, so I can understand adding the factory keyword,

Is it necessary to use the factory constructor even in the Album class of this Complete example?

In the case of the Album class, since the normal constructor is used in the factory constructor, I feel that this factory constructor (Album.fromJson) always creates a new instance. In fact

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');
  }
}

As you can see, it seems that it works without any problems even if I try using only the normal constructor.

Is there any advantage to preparing and using a factory constructor?

Or is there something wrong without using the factory constructor in this situation?

I'm not sure when to use the factory constructor in the first place, Is there a clear definition?

1
  • 2
    I don't see any reason why Album.fromJson needs to be a factory constructor. It could be implemented with a redirecting constructor instead. That example possibly used factory for consistency (or out of habit) with .fromJson constructors using json_serializable or built_value, and those must use factory constructors.
    – jamesdlin
    Commented Aug 28, 2020 at 7:12

2 Answers 2

6

Before diving into factory as keyword in flutter, you might have a look at Factory as design pattern to have the full picture in mind.

The main benefit of using factory design pattern

That is, the Factory Method design pattern defines an interface for a class responsible for creating an object, hence deferring the instantiation to specific classes implementing this interface. This resolves the issue of creating objects directly within the class which uses them. Also, it enables compile-time flexibility via subclassing. When objects are created within the class, it is very inflexible since you cannot change the instantiation of the object independently from the class — the class is committed to a particular object. By implementing the pattern, subclasses can be written to redefine the way an object is created.

For more info, see here

and as docs refers

Use the factory keyword when implementing a constructor that doesn’t always create a new instance of its class. For example, a factory constructor might return an instance from a cache, or it might return an instance of a subtype. Another use case for factory constructors is initializing a final variable using logic that can’t be handled in the initializer list.

So it's all about hiding the creation logic from outside world.

And of course you can do the following

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

But if you did that in many different components or classes let's say, so whenever you change the logic behind the creation of Album object you will be in-need to change it over all places.

On the other hand the classes which use Album class they only care about having an Object of Album, they care not about how it got instantiated, so if you put the logic of having an instance outside the class itself you are going into what's called spaghetti code

3

You can use factory to test for example if the json data returned by som request is null so you return a null dirctly by the use of factory named constructor for example look at this

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.