Flutter factory keyword

I have seen factory several times in Flutter . I didn't pay much attention to it before I used it, but I saw it today, so I want to know what he does.

I searched for "Flutter factory keyword" in Baidu, basically there are two blogs, the rest are excerpts from each other, and I didn't say why, so I was more curious, I read blog by blog, and still read Nothing new.

The use of the factory keyword in dart Factory in
flutter (the only object on the constructor) and the singleton pattern

There is a saying:
use the factory keyword when you need the constructor to not create a new object every time

Then the example given:

class Manager {
  // Factory pattern: singleton exposes access point
  factory Manager() => _getInstance();

  static Manager get instance => _getInstance();

  // static private member, not initialized
  static Manager _instance;

  // private constructor
  Manager._internal() {
    // initialize
  }

  // static, synchronized, private access point
  static Manager _getInstance() {
    if (_instance == null) {
      _instance = new Manager._internal();
    }
    return _instance;
  }
}

main() {
  // No matter how you initialize, you get the same object
  Manager manager1 = new Manager();
  Manager manager2 = Manager.instance;
  Manager manager3 = new Manager();
  Manager manager4 = Manager.instance;
  print(identical(manager1, manager2)); //true
  print(identical(manager1, manager3)); //true
  print(identical(manager3, manager4)); //true
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

Then another piece of blog:

class Singleton {
  static final Singleton _singleton = Singleton._internal();

  factory Singleton() {
    return _singleton;
  }
  
  Singleton._internal();
}

main() {
  var s1 = Singleton ();
  var s2 = Singleton();
  print(identical(s1, s2));  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

The comparison of the two pieces of code is that the first paragraph is a bit more, and then the use is optimized, but the second piece of code is the one that hits the nail on the head;
still look at the sentence:
when you need a constructor, don’t create a new one every time object, use the factory keyword

The first piece of code to look at the use of the factory is to call the _getInstance() method, and then the _getInstance() method is a judgment of whether to initialize, if not, call the constructor , that is, call a private constructor here function; after looking at the whole process, I did not see the role of the factory;
its external use is to call the _getInstance() method internally, and the initialization inside the _getInstance() method is only done once from beginning to end.

The second piece of code is relatively straightforward. There is a private constructor and an external public constructor . The initialization only calls the external factory-modified public constructor. No matter how many times it is called, the statically initialized variable is always returned. In this case, I can just call the static variable directly. What does the factory do?

Use the factory keyword when you need the constructor to not create a new object each time

The most straightforward interpretation of that sentence is:

class SingleInstance{

  factory SingleInstance(){};

}

main(){
	val s1=SingleInstance();
	val s2=SingleInstance();
	//Theoretically s1==s2
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

But it is observed that there is no such way of writing, the factory-modified constructor must have a corresponding constructor return value. In other words, the return value needs to be unique to ensure its singleton, not the uniqueness of the factory-modified constructor;

So in conclusion, the factory is used to modify the name of the public constructor (I tried to change the name, but found that it is not allowed), and then it has a return value; its meaning is to make the constructor become a A method that returns a value, so the return value has a lot of room for manipulation; to a certain extent, this modified method is no longer a constructor, it is a bag method with a constructor certificate (with a return value) , and the return value type is also fixed to an instance of this class type (and subclasses);

This is the first method I caught, used to make a singleton, with this special trick to make a singleton, I can do it another way:

class SingleInstance {
  static final SingleInstance _singleInstance = SingleInstance._internal();

  static SingleInstance get singleton => _singleInstance;

  SingleInstance._internal();
}

  void mian() {
    var s1 = SingleInstance.singleton;
    var s2 = SingleInstance.singleton;
    //s1==s2 is also established
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

So factory just shows that it has the feature with return value and binds the constructor firmly, so it has the single feature of constructor.

Replacing it with something like this is nothing:

class SingleInstance {
  static final SingleInstance _singleInstance = SingleInstance._internal();

  //static SingleInstance get singleton => _singleInstance;

  factory SingleInstance(){
    return SingleInstance._internal();
  }

  SingleInstance._internal();
}
  void mian() {
    var s1 = SingleInstance ();
    var s2 = SingleInstance();
    //s1==s2 is not established
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

The first article shows a total of three scenarios, singleton is one, and there is a cache instance, its effect is equivalent to a singleton, but a Map is used to construct multiple instances according to different input parameters, but the input If the parameters are the same, the same instance will be returned at the time of acquisition. This only shows a usage scenario and has no particularity;

There is also a factory pattern. Aside from the factory pattern, when you instantiate a class with a specified class name, it returns an instance of the class you specified, not an instance of a subclass; simply looking at instantiation, the instance of It is the class itself; and because the factory has a return value and the return value is an instance of the class and its subclass, it can write the name of the parent class to initialize the subclass during initialization;

When I wrote this, I thought I would add a sentence: Any returned reference is still limited by the parent class and it ends; but I changed something;

The original example is:

abstract class Animal {
  String name;
  void getNoise();
  factory Animal(String type,String name) {
    switch(type) {
      case "cat":
        return new Cat(name);
      case "dog":
        return new Dog(name);
      default:
        throw "The '$type' is not an animal";
    }
  }
}

class Cat implements Animal {
  String name;
  Cat(this.name);
  @override
  void getNoise() {
    print("${this.name}: mew~");
  }
}

class Dog implements Animal {
  String name;
  Dog(this.name);
  @override
  void getNoise() {
    print("${this.name}: wang~");
  }
}

int main(){
  var cat = new Animal("cat","wiki");
  var dog = new Animal("dog","baobao");
  cat.getNoise();
  dog.getNoise();
  return  0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

Combined with what I said above, the real instances of cat and dog returned here should be the corresponding Cat and Dog; according to Java's thinking, the parent class reference points to the subclass object; then cat and dog should be Animal references, but The instance is the specific corresponding type;
I changed something;

class Dog implements Animal {
  String name;
  Dog(this.name);
  @override
  void getNoise() {
    print("${this.name}: wang~");
  }
  void wang(){
  	print("--------wang--------");
  }
}

int main(){
  var cat = new Animal("cat","wiki");
  Dog dog = new Animal("dog","baobao");
  cat.getNoise();
  dog.getNoise();
  dog.wang();
  return  0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

In the Dog class, I added a wang() method. In the main function, I pointed the reference pointed to by dog ​​directly to Dog, and then called the wang() method, which was executed correctly. . . .

On the surface, the current code looks like the subclass reference points to the parent class instance (of course we know that the subclass instance is returned directly).

But how awkward it is, I even thought that Dart had the property of subclass references pointing to instances of the parent class.

I quickly re-wrote a normal example

class Parent {

}

class Child extends Parent{
  void main(){
    Child child = new Parent();
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

I was relieved when I saw the bright red line on the code reporting that this was not allowed.

Originally, learning is a process of climbing up a hill. You haven’t reached the middle of the mountain, but someone tells you that the top of the mountain you see is not the top of the mountain, and that going up and down is not the same road at all.

Looking at the special example, I found that even the inheritance of abstract classes is not the extends keyword, but implements. Isn't this how the interface is written?

When I changed to extends, it gave the following error:

The class ‘Cat’ cannot extend ‘Animal’ because ‘Animal’ only has factory constructors (no generative constructors), and ‘Cat’ has at least one generative constructor.
Try implementing the class instead, adding a generative (not factory) constructor to the superclass Cat, or a factory constructor to the subclass.

One of the amendments is to change to implements.

A supplementary knowledge point is that Dart's abstract classes and interfaces are written in the same way, both abstract.

The above is summed up as:

Factory is specially used to decorate constructors, and its feature is to bring a return value, and the return value type is the modified class or subclass; you can use this feature to achieve what you want in different scenarios.

Another feature is not finished above, but I haven't studied and understood it, that is, implements, which is temporarily stranded.

I'm doing research while writing, so I don't have much depth, and when it's time to get off work, the question above will be stranded.


Related: Flutter factory keyword