DEV Community

Cover image for Dart: Singleton Demystified
Monday Solomon
Monday Solomon

Posted on

Dart: Singleton Demystified

The Singleton pattern in Dart is a way to ensure that a class has only one instance and provides a global point of access to it. It helps eliminate redundant code by allowing you to use a single line of code to access the instance.

In Dart and Flutter, this pattern is often used when showing snack bars or confirmation dialogues to the user. It ensures that only one instance of the class responsible for displaying these UI elements exists and can be accessed from anywhere in the application.

We will demystify the topic into two sections;

Section 1: Understanding Singletons in Dart

In Dart, a singleton is a design pattern that enables you to have only one instance of a class throughout your application. It ensures that there is a single point of access to that instance, which can be useful in scenarios where you need to manage a shared resource or maintain a global state.

To implement a singleton in Dart, you typically define a class with a private constructor and a static instance variable. You provide a factory constructor that returns the single instance of the class, ensuring that only one instance is created.

Let's dive into an example to illustrate how a singleton works in Dart:

class MySingleton {
  static MySingleton _instance;

  factory MySingleton() {
    _instance ??= MySingleton._();
    return _instance;
  }

  MySingleton._();

  void doSomething() {
    print('Doing something...');
  }
}

Enter fullscreen mode Exit fullscreen mode

In the above code, the MySingleton class has a private constructor _() and a static instance variable _instance. The factory constructor checks if _instance is null, and if so, it creates a new instance. If _instance is not null, it simply returns the existing instance.

Not so difficult right ?,
Leggo 🚀🚀🚀

To use the MySingleton class, you can create instances as follows:

void main() {
  var singleton1 = MySingleton();
  var singleton2 = MySingleton();

  print(identical(singleton1, singleton2)); // Output: true

  singleton1.doSomething(); // Output: Doing something...
  singleton2.doSomething(); // Output: Doing something...
}

Enter fullscreen mode Exit fullscreen mode

In the main() function, we create two instances of MySingleton using the constructor MySingleton(). However, since MySingleton is a singleton class, both singleton1 and singleton2 refer to the same instance of the class. The identical() function confirms that they are the same object.

By using the singleton pattern, you ensure that only one instance of the class exists, and you can access it from anywhere in your application. This can be useful in scenarios where you want to share data, maintain a global configuration, or provide a central point of access to a resource.

Section 2: Understanding Singletons with a Simple Analogy

Understanding the concept of singletons can be easier with a simple analogy. Let's use the example of a music player in your phone.

Think of a music player on your phone. You can only have one instance of the music player at a time. No matter how many times you try to open the music player from different apps or screens, it's always the same music player that appears, with the same song playing.

In code, a singleton class works similarly:

class MusicPlayer {
  static MusicPlayer _instance;

  factory MusicPlayer() {
    _instance ??= MusicPlayer._();
    return _instance;
  }

  MusicPlayer._();

  void playSong(String song) {
    print('Playing song: $song');
  }
}
Enter fullscreen mode Exit fullscreen mode

In this example, MusicPlayer is the singleton class. It has a private constructor _() and a static instance variable _instance. The class provides a factory constructor that checks if an instance exists. If it does, it returns that instance; otherwise, it creates a new instance and returns it.

To use the MusicPlayer singleton:


void main() {
  var player1 = MusicPlayer();
  var player2 = MusicPlayer();

  player1.playSong('Some Song'); // Output: Playing song: Some Song
  player2.playSong('Another Song'); // Output: Playing song: Another Song
}
Enter fullscreen mode Exit fullscreen mode

In this example, player1 and player2 are both instances of MusicPlayer. However, since MusicPlayer is a singleton class, they refer to the same instance. So, when you call the playSong() method on either player1 or player2, it operates on the same music player and plays the requested song.

The singleton pattern ensures that you have only one instance of a class and that you can access it from anywhere in your code.

Implementing singletons in Dart can provide significant benefits when managing shared resources or global states in your application.

Thank You 🤗🤗,
Happy Coding 👨🏿‍💻

Top comments (0)