Flutter Design Patterns: 1 — Singleton

An overview of Singleton design pattern and its implementation in Dart and Flutter

First of all, I would like to thank you all for the support after publishing the introduction article to this series. Honestly, I have not expected that amount of people to not only be interested in the creation of mobile applications using Flutter but who are also willing to learn more about the Dart language itself, OOP design patterns and their appliance, code architecture or software engineering in general. This encouraged me to dive straight into the research, coding, and hence, I present you the first design pattern in the series — Singleton.


Table of Contents

  • Analysis
  • Implementation
  • Other articles in this series
  • Your Contribution

What is Singleton?

Highlander — There Can Be Only One

Singleton is a creational design pattern which ensures that a class has only one instance and also provides a global point of access to it. The motivation for this pattern is stated in the GoF book:

It’s important for some classes to have exactly one instance. Although there can be many printers in a system, there should be only one printer spooler. There should be only one file system and one window manager…

The main idea of this pattern is to make a class itself responsible for keeping track of its sole instance. Singleton is considered as one of the simplest design patterns but it is also an easy one to get wrong if you are not careful. So let’s move to the analysis and clarify the details of Singleton and its implementation.


Analysis

Class diagram and basic structure

Class Diagram — Singleton
  • Singleton class contains the static property instance which is a reference to the class instance itself (this relationship is represented as an association link from the class Singleton to itself);
  • This instance is only accessible through the static method getInstance();
  • Class constructor is marked as private (it could be protected in other implementations) to ensure that the class could not be instantiated from outside the class.

Applicability

General thoughts and dangers

  • In general, the Singleton class should not require parameters for its construction. If your class design requires a parameter, it could lead to the creation of a somehow different object based on that parameter — could this class still be called a Singleton, then? Some resources state that this is a valid approach, but I have a different opinion;
  • Thread safety — you should be aware of Singletons in multi-threaded applications. If they hold some kind of mutable data, it could lead to unexpected results, so the synchronization mechanism should be considered.
    Since we are talking about the Dart programming language in this series, you should know that Dart is a single-threaded programming language and its code runs in a little isolated space on the machine, called isolate. Hence, you should not worry about the thread-safety when implementing Singletons in Dart as long as you do not create a new separate isolate from the code by yourself. If you are not familiar with this topic, I strongly recommend you to watch this video about isolates and event loops in Dart and Flutter.
  • In some cases, the Singleton design pattern is considered an anti-pattern. That is because it violates one (actually, more than one, but this example, in my opinion, is the best one) of the SOLID principles — the single responsibility principle. In addition to the main responsibility of the Singleton class, it should also manage its instance lifetime which is a separate concern. Also, the use of Singletons makes it difficult to unit test the code since it is not possible to mock a Singleton unless you provide some kind of interface that serves as its type.

Implementation

  • Using a Singleton design pattern which is implemented by definition;
  • Using a Singleton design pattern which is implemented using the Dart language capabilities;
  • Without using a Singleton at all.

ExampleStateBase

As already mentioned, the example’s state consists only of a single String property stateText and its initial value initialText. Properties stateText ant initialText are marked as protected — it is needed to make these properties accessible only for those classes which extend the ExampleStateBase class. However, Dart does not support the protected visibility in the same way as some of you could expect it to be coming from the other OOP language’s background such as C# or Java — we can only annotate these properties as protected but it is more as a reminder for the developer not to use them from outside of the class scope (Visual Studio Code editor even shows a warning in this case). Also, ExampleStateBase provides methods to operate the stateText.

Singleton’s implementation by definition

Class Diagram — Implementation of the Singleton design pattern
  • ExampleStateByDefinition extends the ExampleStateBase class to obtain access to the state (in this case, stateText and initialText) and its methods.
  • ExampleStateByDefinition implements the Singleton design pattern and handles the instance creation. The instance is only accessible through the static method getState().

Code of the ExampleStateByDefinition:

Singleton’s implementation using Dart magic

Class ExampleState implements a Singleton design pattern “the Dart way”:

By comparing this code with the previous implementation, you could notice that the static method getState() is missing — well, it is just not needed anymore! Dart language provides a factory constructor. It is used to implement a constructor that does not always create a new instance of its class — it is a nice and elegant way to implement the class as a Singleton, isn’t it? Now you can create the instance of ExampleState class by calling its factory constructor in the same manner as you would do that by calling a default one — factory constructor will create a new instance or return the existing one if it was already initiated.

ExampleStateWithoutSingleton

Example

The example itself uses all three different implementations of the state:

Singleton implementations (ExampleStateByDefinition and ExampleState) create a new state object only on the first creation of the SingletonExample widget, but the ExampleStateWithoutSingleton instance is created on each creation of the SingletonExample widget. This behaviour could be noticed by changing the state and forcing the example’s widget to rebuild e.g. by switching tabs:

Or by navigating to the main menu and back:

As you can see, the state which is implemented as a Singleton remains the same since a new instance of the state class is not created on example’s widget rebuild.

All of the code changes for the Singleton design pattern and its example implementation could be found here.



Your contribution

Flutter Community

Articles and Stories from the Flutter Community

Mangirdas Kazlauskas

Written by

Software Engineer | Flutter Enthusiast https://www.linkedin.com/in/mangirdas-kazlauskas/

Flutter Community

Articles and Stories from the Flutter Community

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade