avatarMax Zimmermann 💡

Summary

This text discusses the use of factory constructors in Dart/Flutter and their applications, such as implementing the singleton pattern, deserialization, instantiating subclasses, and improving readability.

Abstract

Factory constructors in Dart/Flutter are not essential for creating Flutter apps but can be helpful for various use cases. They can be used to implement the singleton pattern, which allows only one object of a class to be instantiated. Factory constructors can also be used for deserialization, mapping data from a map to an object, and instantiating subclasses. The syntax of factory constructors is easier to write and read, which can be useful for some use cases like singletons or instantiating subclasses. However, factory constructors can most often be replaced by static methods. This text highlights the differences between factory constructors and static methods, referencing Remi Rousselet's article on the subject.

Opinions

  • Factory constructors are not essential for creating Flutter apps but can be helpful for various use cases.
  • Factory constructors can be used to implement the singleton pattern, which allows only one object of a class to be instantiated.
  • Factory constructors can also be used for deserialization, mapping data from a map to an object, and instantiating subclasses.
  • The syntax of factory constructors is easier to write and read, which can be useful for some use cases like singletons or instantiating subclasses.
  • Factory constructors can most often be replaced by static methods.
  • The text highlights the differences between factory constructors and static methods, referencing Remi Rousselet's article on the subject.
  • Factory constructors can improve readability and make code easier to understand.

Dart/Flutter: What Are Factory Constructors? (Advanced Knowledge)

You will learn how factory constructors work and when to use them.

“A hand-drawn factory” created with DALL-E2 and PhotoVibrance [affiliate link]

Table of Contents

Introduction When to use them?Singleton patternDeserializationInstantiate subclassSyntax sugar What is the difference between a factory constructor and a static method? Conclusion Resources More articles

Introduction

Factory constructors are nothing you need to program a Flutter app. Nevertheless, they can be useful for different use cases. Factory constructors can be helpful to implement the singleton pattern, use deserialization, instantiate subclasses, or improve readability. Often factory constructors and static methods look like they are the same. After reading the article you will understand the differences. In general, this is a more advanced topic that addresses people with a basic understanding of Dart (and Flutter) who want to expand their knowledge.

When to use them?

In the following, I describe different use cases for which factory constructors make sense with code examples.

Singleton pattern

If you implement the singleton pattern, you only allow to instantiate one object of a class. This makes sense if you have complex classes that require heavy computation or allow only one access, e.g. for a database for which an example is provided in the following. You can play around with the following example on this DartPad.

The database object is created at (1). The creation of an object can only be done once inside the class because of “._internal” (2). When you the factory it always returns the same database object (3). Using factories is an easy way to implement singletons.

class Database {
  static final Database _database = Database._internal(); // (1)

  factory Database() => _database; // (3)

  Database._internal(); // (2)
}

// Create the singleton

void main() {
  Database db = Database();
  Database db2 = Database();
  print(identical(db, db2)); // true
}

Deserialization

Most apps need API calls. When you get the information as a map you most often want to create classes to continue working with the information. With a factory, you can take a map as input and give an object as output. You can try the example of the deserialization of a user on this DartPad.

In the example, you extract the user data from a map (1), which is a quite common scenario. When the factory is called (2) it maps the chosen keys as attributes of a user object (3).

class User {
  final String name;
  final int age;

  User({required this.name, required this.age});

  factory User.fromJson(Map<String, dynamic> json) => User(
        name: json['name'],
        age: json['age'],
      ); // (3)
}

// Use deserialization

void main() {
  final karlMap = {
    'name': 'Karl',
    'age': 32,
  }; // (1)

  final karl = User.fromJson(karlMap); // (2)

  print(karl.name); // Karl
  print(karl.age); // 32
}

Instantiate subclass

With factory constructors, you can instantiate different subclasses of your parent class. This can be useful if you want to create a subclass randomly or depending on time.

Imagine you want to create a game. In this game, you encounter at first easy enemies that get more powerful as time goes by. A ghost (1) is an easy enemy and a dragon (2) is a difficult enemy. As time progresses, the game becomes more difficult and you encounter more dragons (3,4). This can also be done by letting a static method decide which subclass should be returned but with a factory constructor, this can be implemented slightly more elegant. Here is how you could implement this with code. You can try it on this DartPad.

class Enemy {
  final int strength = 0;
  final String name = '';

  factory Enemy.getEnemy({required int timeInSeconds}) {
    if (timeInSeconds < 1000) {
      return Ghost();
    } else {
      return Dragon();
    }
  }
}

class Ghost implements Enemy { // (1)
  @override
  final int strength = 10;

  @override
  final String name = "Ghost";
}

class Dragon implements Enemy { // (2)
  @override
  final int strength = 100;

  @override
  final String name = "Dragon";
}

void main() {
  Enemy enemy = Enemy.getEnemy(timeInSeconds: 1); // (3)

  print(enemy.strength); // prints 10
  print(enemy.name);     // prints Ghost

  Enemy enemy2 = Enemy.getEnemy(timeInSeconds: 1000); // (4)

  print(enemy2.strength); // prints 100
  print(enemy2.name);     // prints Dragon
}

Syntax sugar

Sometimes it makes sense to use a factory constructer over a static function because the syntax is easier to write and understand. The differences get covered in the following chapter What is the difference between a factory constructor and a static method?

What is the difference between a factory constructor and a static method?

Most often, a factory could also be replaced by a static method. So why do you need factory constructors? Flutter legend Remi Rousselet, creator of packages like provider, riverpod, and freezed, wrote a great article about The difference between a “factory constructor” and a “static method”. I just list his findings here. For further explanations and code examples, I want to reference his blog post.

Remi Rousselets’ package freezed uses the factory constructor in combination with code generation. I recommend looking at the syntax after reading his article to see how he used the factory constructor in combination to speed up your development process.

  • Factory constructors can be unnamed.
  • A factory constructor doesn’t need to specify the generic parameters.
  • Specifying a factory-named constructor removes the default constructor.
  • Factory constructors have a short-hand syntax for redirecting to another constructor.
  • Factory constructors can be declared as const .
  • Factory constructors can’t be async. (This point is from the comments of the article)

Conclusion

Factory constructors most often can be replaced by static methods. For some use cases, they have an advantage because the code is easier to write and read. This can be the case for singletons or for instantiating subclasses. Do you have questions or something to add? Then share your thoughts in the comments. Also, let me know if you have a topic in mind that I should cover in my next article. Any feedback is highly appreciated!

If you liked the article clap (50x), highlight, comment, and share it. Not only but especially technical articles got disadvantaged by the new Medium Partner Program incentives. If you want to support your favorite (technical) writers on Medium, remember to interact with the articles. You find more information about this here: The New Medium Partner Program is Bad for Quality Writing!

Resources

More articles

Software Development
Software Engineering
Flutter
Programming
Technology
Recommended from ReadMedium