Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing ways to create singletons in Dart

Tags:

singleton

dart

I read these posts:

  • How do you build a Singleton in Dart?
  • How to implement Singleton pattern in Dart using factory constructors?
  • Object Structures in Dart

I'm having a little trouble understanding the difference between the following ways of creating singletons:

1. Factory constructor

class SingletonOne {    SingletonOne._privateConstructor();    static final SingletonOne _instance = SingletonOne._privateConstructor();    factory SingletonOne(){     return _instance;   }  } 

2. Static field with getter

class SingletonTwo {    SingletonTwo._privateConstructor();    static final SingletonTwo _instance = SingletonTwo._privateConstructor();    static SingletonTwo get instance { return _instance;}  } 

3. Static field

class SingletonThree {    SingletonThree._privateConstructor();    static final SingletonThree instance = SingletonThree._privateConstructor();  } 

These are instantiated like this:

SingletonOne one = SingletonOne(); SingletonTwo two = SingletonTwo.instance; SingletonThree three = SingletonThree.instance; 

Questions

Günter Zöchbauer said about this question:

There is no need to use the factory constructor. The factory constructor was convenient when new was not yet optional because then it new MyClass() worked for classes where the constructor returned a new instance every time or where the class returned a cached instance. It was not the callers responsibility to know how and when the object was actually created.

I don't understand how new being optional now makes the factory constructor unnecessary now. Before you couldn't do something like SingletonTwo or SingletonThree above?

Günter Zöchbauer also said:

You can also change static final DbHelper _db = new DbHelper._constr(); to static final DbHelper singleton = new DbHelper._constr(); and remove the singleton getter I suggested in my answer. It depends on your use case. You might not be able to use a field initializer if you need additional config values to create the instance. In your example it would be sufficient though.

What are the use cases for each of the singleton patterns above (SingletonOne, SingletonTwo, and SingletonThree)? It would be helpful to see an example for each. Wouldn't the factory pattern be useful if you wanted to hide the fact that the class was a singleton (as described here)?

like image 242
Suragch Avatar asked Jan 06 '19 01:01

Suragch


People also ask

What are the different ways to create singleton?

There are two forms of singleton design pattern, which are: Early Instantiation: The object creation takes place at the load time. Lazy Instantiation: The object creation is done according to the requirement.

What is the best way to subclass singletons?

I would argue the most common way to implement a singleton is to use an enum with one instance. That might be a "better" way but definitely not the most common way. In all the projects I have worked on, Singletons are implemented as I have shown above.

How many types of singleton are there?

There are two types of singleton implementations: eager and lazy initialization.

Can you have multiple singletons?

Well-designed singleton can have only one instance per application. Creating of multiple instances is a mistake in the application design. It might happen in some cases, e.g.: Non thread safe singleton with lazy initialization: several threads are trying to get an instance and creates multiple instances.


2 Answers

As Günter Zöchbauer stated in the comments, each of the three ways you listed of creating singletons are the same. Use your personal preference to choose one.

I'm going to add some additional notes:

  • SingletonOne when instantiated looks like any other class. So you could use this one if you want to hide the fact that it is a singleton (and leave the option to make it not be a singleton in the future). You could also pass in arguments in the constructor.
  • SingletonTwo would allow you to do other work before returning the instance.
  • SingletonThree is the shortest, and short clean code is desirable in my book, all other things being equal.
like image 129
Suragch Avatar answered Sep 23 '22 09:09

Suragch


Since Dart allows root-level variables, a perfectly good, lazy loading Singleton can be had thusly:

final store = _Store();  class _Store { // } 

Limitations

Like your three other examples, this won't work if you need asynchronous construction. Also, like SingletonTwo and SingletonThree you can't pass in any arguments from the calling scope.

For a singleton that needs async construction and arguments I would use something like this:

class StoreService {   static StoreService? _instance;    StoreService._() {}    static Future<StoreService> instance() async {     // we can await things here          if (_instance == null) {       _instance = StoreService._();     }      return _instance!;   } } 
like image 20
Jannie Theunissen Avatar answered Sep 22 '22 09:09

Jannie Theunissen