Dart – implementing the Singleton pattern with factory constructors

In Dart there is an inter­est­ing lan­guage fea­ture called ‘Fac­to­ry Con­struc­tors’, which effec­tive­ly allows you to over­ride the default behav­iour when using the new key­word – instead of always cre­at­ing a new instance the fac­to­ry con­struc­tor is mere­ly required to return an instance of the class, the dif­fer­ence is impor­tant.

Fac­to­ry con­struc­tors allow you to imple­ment a num­ber of tech­niques and pat­terns with­out alter­ing code that con­sumes your class. For instance,

  • Sin­gle­ton pat­tern which we will look at more close­ly.
  • Object pool­ing, a use­ful tech­nique for reduc­ing the amount of allo­ca­tions (and its asso­ci­at­ed allo­ca­tion cost and con­se­quent GC pres­sure) in per­for­mance crit­i­cal appli­ca­tions.
  • Fly­weight pat­tern which is already dis­cussed in more detail in this Idiomat­ic Dart arti­cle.

These are just 3 use cas­es that I can think of off the top of my head, please feel free to sug­gest any more that I have missed.

Problems with common Singleton pattern implementations

In oth­er lan­guages (well, the ones that I’m famil­iar with any­way!), in order to imple­ment the Sin­gle­ton pat­tern you have to ensure that the class’s con­struc­tor is not exposed pub­licly and that access to the sin­gle­ton instance is done via a sta­t­ic Sin­gle­ton prop­er­ty. Revered C#/Java devel­op­er Jon Skeet has a very good arti­cle on the var­i­ous solu­tions one might adopt to imple­ment the sin­gle­ton pat­tern in C#.

Inflex­i­ble

These imple­men­ta­tions require code that con­sumes your class to be aware of its imple­men­ta­tion of the sin­gle­ton pat­tern and cre­ate a vast blast radius through­out your appli­ca­tion should you one day decide that the sin­gle­ton pat­tern is no longer necessary/applicable.

For instance, if assump­tions in your appli­ca­tion change dras­ti­cal­ly (and they often do..) and you need to switch to the fly­weight or anoth­er pat­tern instead to cater for chang­ing require­ments and/or assump­tions.

Unin­ten­tion­al tight cou­pling

In the case of C# (where sta­t­ic mem­bers are not allowed on inter­faces and abstract class­es are un-con­structible) the stan­dard sin­gle­ton pat­tern also cre­ate tight cou­pling to a con­crete imple­men­ta­tion where it’s sel­dom nec­es­sary.

You can, to some degree, work around this issue of tight cou­pling by intro­duc­ing an IOC con­tain­er as mid­dle man between your class and its con­sumers, most IOC con­tain­ers pro­vide some mech­a­nism for con­trol­ling object lifes­pans (tran­sient, sin­gle­ton, pooled, etc.). How­ev­er, you now have tight cou­pling to the IOC con­tain­er instead…

Singleton pattern with Factory constructors

You can imple­ment the sin­gle­ton pat­tern using fac­to­ry con­struc­tors like this:

the key thing here is that any con­sum­ing code is com­plete­ly obliv­i­ous to the fact that we have just imple­ment­ed the sin­gle­ton pat­tern. If we were to con­tin­ue our mind lat­er or forced to adopt a dif­fer­ent pat­tern because of chang­ing require­ment, there will be triv­ial or no change on all the con­sum­ing code!

Links

Idiomat­ic Dart — Fac­to­ry con­struc­tors

Jon Skeet – Imple­ment­ing the Sin­gle­ton pat­tern in C#