Factory constructor Flutter : when to use

Why do we need factory constructor in flutter? Moreover, when to use the factory constructor?

Firstly, we have been building a web app with Flutter 3.0. As a result, now we can generate the same output on the web as we usually do in mobile.

You may ask, could we not do that before?

Before we discuss factory constructor, let’s clarify this part. 

On the web, we couldn’t use the NetworkImage() widget constructor directly.

Consider the following code.

CircleAvatar(
                  radius: 70,
                  backgroundImage: NetworkImage(
                    'https://cdn.pixabay.com/photo/2018/03/24/00/36/girl-3255402_960_720.png',
                  ),
                ),

Before Flutter 3.0 release if we issued the command :

flutter run

It would throw an error – “Trying to load an image from another domain?”

As a result, we had to issue the following command to avoid the error.

flutter run -d chrome --web-renderer html

For example, Flutter 3.0 has solved these small little problems.

However, the concept of using factory constructor in flutter has not changed.

Although we have not used factory constructor before, yet in our ongoing flutter web app series we might need to implement this important concept.

Factory constructor in flutter, what is the difference

When we have a normal generative constructor in a class, why do we need a factory constructor in flutter?

That’s the first question.

Secondly, we pass values through flutter widget constructors. 

A generative constructor is a function that always returns a new instance of the class. That’s why it doesn’t use the return keyword.

Apart from the unnamed generative constructor, we can also use the named generative constructors which we often do.

Still the question remains.

Why do we need the factory constructor?

To explain why we need a factory constructor in flutter and what is the difference with a generative constructor, let’s see a code example.

class Piano {
  late final String sound;
  bool mute = false;

  Piano._internal(this.sound);

  static final Map<String, Piano> _privateLibrary = <String, Piano>{};

  factory Piano(String sound) {
    if (_privateLibrary.containsKey(sound)) {
      return _privateLibrary[sound]!;
    } else {
      final piano = Piano._internal(sound);
      _privateLibrary[sound] = piano;
      return piano;
    }
  }

  void play(String message) {
    if (!mute) print(message);
  }
}

void main() {
  var piano = Piano('sound');
  piano.play('It\'s playing');
}

// output: It's playing

Before discussing the above code, let’s remember a few points about the factory constructor in flutter.

When the generative constructor is expensive and we don’t want to return a new instance of the class, we need a factory constructor.

Why?

Let’s try to understand.

What happens in our code?

With the help of the factory constructor, we can control the flow to determine what object to return and we have utilised the return keyword.

Factory constructor and control flow

However, we couldn’t do the same thing with the generative constructor. 

Certainly in our code, a factory returns a new class instance and to do that it has called a named generative constructor.

Piano._internal(this.sound);
...
factory Piano(String sound) {
    if (_privateLibrary.containsKey(sound)) {
      return _privateLibrary[sound]!;
    } else {
      final piano = Piano._internal(sound);
      _privateLibrary[sound] = piano;
      return piano;
    }
  }

In our code, the unnamed factory constructor first tries to read from a Map property. Right?

static final Map<String, Piano> _privateLibrary = <String, Piano>{};

Because the Map property is static, it is independent of any instance variable. 

If an instance of Piano already exists, it’s returned.

Otherwise, we generate a new instance by calling the named generative constructor.

Piano._internal(this.sound);

The Map property stores its value and then returns.

Since the named generative constructor takes only one parameter, the “mute” property remains false while initialising.

Here is the biggest advantage of using a factory constructor.

What?

With a setter, we can change the “mute” property to true.

And in that case, the piano will not play. Therefore we won’t get any output.

As we progress we will find more use cases of factory constructor in flutter.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

Courses at Educative

GitHub repository

Technical blog

Twitter

Comments

Leave a Reply