DEV Community

Cover image for Design Pattern #1 - Singleton
Vitor Norton for SuperViz

Posted on • Edited on • Originally published at superviz.com

Design Pattern #1 - Singleton

I’m excited to be starting a new series where we’ll dive a bit into some of the trending design patterns for front-end developers.

Design patterns are a crucial part of software development, offering tried and tested solutions to common problems that can be used to improve collaboration when working with many people on the same project.

In this first article, we’ll be exploring the Singleton pattern that ensures a class has only one instance and provides a global point of access to it. Stay tuned for more articles exploring different design patterns in this series.

Singleton Pattern

The Singleton Pattern is a type of design pattern that restricts the creation of a class to only one instance. This is useful in scenarios where a single point of control or coordination is required. In other words, it ensures that a class has only one instance, and provides a global point of access to it.

This pattern is often used for configuration data, caches, or connection pools or logging where it's more efficient to have one instance running that can be used by other processes in an application. It also can be useful when you need to maintain state, initialize fields or manage a queue of calls and callbacks.

For instance, if an application has a dropdown list of items that is accessed from various places, a Singleton can manage this shared resource. This ensures that if the list is modified in one place, the changes are reflected across the entire application.

If you need this information to be shared across multiple instances of your application (like different devices), you can use the Real-time Data Engine from SuperViz. Designed with developers in mind, it provides an effortlessly seamless integration into your projects, enabling you to implement design patterns such as the Publisher/Subscriber Pattern. Our engine ensures efficient and real-time updates, transforming your application's responsiveness and overall user experience.

Singleton Example

Here's a basic example of how this dropdown list might be implemented in JavaScript:

let dropdownListItems;
class DropdownList {
    constructor(items = []) {
        if (dropdownListItems) {
            return dropdownListItems;
        }

        dropdownListItems = items;
    }

    addItem(item) {
        dropdownListItems.push(item);
    }

    removeItem(item) {
        dropdownListItems = dropdownListItems.filter(i => i !== item);
    }
}

const dropdownList = new DropdownList();
export default dropdownList;

Enter fullscreen mode Exit fullscreen mode

This JavaScript code defines a class DropdownList and an instance of it.

  1. dropdownListItems is a variable that is initially undefined.
  2. The DropdownList class is defined with a constructor that accepts an array of items as an argument, defaulting to an empty array if no argument is provided.
  3. In the constructor, if dropdownListItems is already defined, it returns the one defined. If dropdownListItems is not defined, it assigns the items argument to dropdownListItems.
  4. The DropdownList class has two methods: addItem and removeItem.
    • addItem method: This method accepts an item as an argument and pushes it to the dropdownListItems array.
    • removeItem method: This method accepts an item as an argument and removes it from the dropdownListItems array. It does this by reassigning dropdownListItems to a new array that filters out the item to be removed.
  5. An instance of DropdownList is created with no arguments, so it will be initialized with an empty array. This instance is stored in the dropdownList constant.

Singleton Pattern with ES2016

The code above shows how to implement the singleton with the ES2015, I choose to show you this way before to make it simpler to understand what the singleton is about.

However, with ES2016 introduced the static keyword, which can be used to create a static instance property on the class. This static instance property can be used to hold the single instance of the class.

class DropdownList {
  static dropdownListItems = [];

  constructor(items = []) {
    if (DropdownList.dropdownListItems.length) {
      return DropdownList.dropdownListItems;
    }
    DropdownList.dropdownListItems = items;
  }

  addItem(item) {
    DropdownList.dropdownListItems.push(item);
  }

  removeItem(item) {
    DropdownList.dropdownListItems = DropdownList.dropdownListItems.filter(i => i !== item);
  }
}

const dropdownList = new DropdownList();

export default dropdownList;
Enter fullscreen mode Exit fullscreen mode

In this ES2016 version, the instance is a static property on the class itself, rather than a separate variable. This makes it clear that the instance is associated with the class, not just some random variable on top.

The instance is created when the module is loaded, and the same instance is returned every time the class is imported. This also means that we don’t need the Object.freeze(player); anymore.

Stay tuned for more posts in this series where we'll continue to explore different design patterns. Don't forget to follow and like if you found this useful, and feel free to leave any questions you have in the comments section.

Top comments (6)

Collapse
 
stretch0 profile image
Andrew McCallum • Edited

Great explanation of singleton patterns, I'm really liking your series on design patterns too.

One thing I found interesting is your use of static on your es16 class.

Whilst your example here does work I would argue that dropDownListItems doesn't need to be a static property. Static properties and methods are usually used to access to properties on the class prototype. So you don't need to use the new keyword to instantiate the class in order to access the property. But, since you're using the singleton pattern, you always have an instantiated class so the static method is superfluous.

You could achieve the same thing with just the following:

class DropdownList {
  dropdownListItems = []; // remove static keyword 

  constructor(items = []) {
    this.dropdownListItems.push(items) 
  }

  addItem(item) {
    this.dropdownListItems.push(item);
  }

  removeItem(item) {
    this.dropdownListItems = this.dropdownListItems.filter(i => i !== item);
  }
}

const dropdownList = new DropdownList();

export default dropdownList;
Enter fullscreen mode Exit fullscreen mode

By removing the static method, it removes confusion about if this class prototype should be accessible.

Otherwise, really nice write up and great explanation of singleton patterns

Collapse
 
rishabh0211 profile image
Rishabh Rastogi

@stretch0 I think your modification of the code does not follow the Singleton pattern since whenever we'll instantiate the DropdownList class, it will create a new dropdownListItems

Collapse
 
juan_labrada_42e0d23118f4 profile image
Juan Labrada

Why there is a value returned from the constructor?

Collapse
 
rishabh0211 profile image
Rishabh Rastogi

Since DropdownList is a singleton class, there should only be a single instance of it. By returning from within the constructor, we are making sure that we get the same dropdownListItems whenever we try to instantiate the class.

const dropdownList1 = new DropdownList();
const dropdownList2 = new DropdownList();
dropdownList1.addItem('test');
console.log(dropdownList2) // logs ['test']
Enter fullscreen mode Exit fullscreen mode
Collapse
 
armantaherian profile image
Arman Taherian

But dropdownList2.addItem('test'); won't work!

Collapse
 
skipperhoa profile image
Hòa Nguyễn Coder

thanks pro