Design Patterns in Action(3)- Singleton

A series of programming design patterns illustration with examples with JavaScript/Python

Photo by Pesce Huang on Unsplash

Creational Pattern — Singleton

Simply put, a Singleton is a pattern where there is only one instance of the class instantiated. This is normally implemented with saving the instance to a static property and having a guard clause to check if the property exist.

Singleton class is normally made accessible globally (though it’s not always the case). This makes the lifecycle of a Singleton class instance persists till the end of the application. This means the instance won’t be garbage collected until the end of the application.

Note why we prefer a Singleton vs. a global variable:

  • Global variables are prone to modification/changes. Local file can easily overwrite the global variable’s value.
  • Multi-thread access can be a problem (Not a case for JavaScript)
  • Namespace pollution and collision. This is especially true for JavaScript. Hence we see the use of Module pattern to implement Singleton.

Singleton is most useful in situations where resource management and access control globally, e.g. a database connection pool, you wouldn’t want to just keeping opening new connections every time you invoke a db operation.

Singleton’s can be implemented with different ways. But normally you will:

  • hide the constructor from the public
  • add a gatekeeper method to lazily evaluate if the instance exists and create one if not

The implementations varies in details like error logging, multi-thread handling, aka. how to make sure the instance is really created only ONCE!

Let’s see an example with Python. The getInstance method is the guard clause. And the __init__ method will raise error if user somehow calls the constructor directly.

class BreadSingleton:

__instance = None

def __init__(self):
if BreadSingleton.__instance:
raise Exception(
"An instance already been initiated !")
else:
BreadSingleton.__instance = self

def bake_bread(self, quantity, name):
self.quantity = quantity
self.name = name

def put_on_shelf(self):
print(f"{self.quantity} of {self.name} are put on shelf!")

@staticmethod
def getInstance():
if not BreadSingleton.__instance:
BreadSingleton()
return BreadSingleton.__instance


oven1 = BreadSingleton.getInstance()
oven1.bake_bread(5, "sourDough")
oven1.put_on_shelf()

oven2 = BreadSingleton.getInstance()
oven2.bake_bread(10, "ciabatta")
oven2.put_on_shelf()

print(oven1 == oven2)
===
5 of sourDough are put on shelf!
10 of ciabatta are put on shelf!
True

However, this will not work in race conditions, where two threads will create a new instance simultaneously at the same time. We can add a check for that with a thread lock:

import threadingclass BreadSingletonTwo:

__singleton_lock = threading.Lock()
__instance = None

def __init__(self):
if not BreadSingletonTwo.__instance:
with BreadSingletonTwo.__singleton_lock:
if not BreadSingletonTwo.__instance:
BreadSingletonTwo.__instance = self
else:
raise Exception(
"An instance already been initiated !")

def bake_bread(self, quantity, name):
self.quantity = quantity
self.name = name

def put_on_shelf(self):
print(f"{self.quantity} of {self.name} are put on shelf!")

@staticmethod
def get_instance():
if not BreadSingletonTwo.__instance:
BreadSingletonTwo()
return BreadSingletonTwo.__instance

There’s also another option by allowing creating multiple instances of the class but keep a shared memory — Borg pattern: http://www.aleax.it/Python/5ep.html

In JavaScript, there’s old and new way of implementing Singleton.

The old way is to use IIFE (Immediately Invoked Function Expression): BreadSingleton below. Note that we delete the constructor after the first time the instance is created, and this will forbid any creation in the future.

class BreadOven {
constructor() {
this._startOven = true;
}
bake_bread(quantity, name) {
this.quantity = quantity;
this.name = name;
}
put_on_shelf() {
return `${this.quantity} of ${this.name} are put on shelf!`;
}
}

const BreadSingleton = (function () {
let breadInstance;

return {
getInstance: function () {
if (!breadInstance) {
breadInstance = new BreadOven();
delete breadInstance.constructor;
}
return breadInstance;
},
};
})();

let oven1 = BreadSingleton.getInstance();
oven1.bake_bread(5, "sourDough");
oven1.put_on_shelf();

let oven2 = BreadSingleton.getInstance();
oven2.bake_bread(10, "ciabatta");
oven2.put_on_shelf();

Another approach is to use Object.freeze . As a result, you won’t be able to make any changes of the instance’s properties or values later on.

Oven.jsclass BreadSingletonTwo {
constructor() {
if (!BreadSingletonTwo.instance) {
this._oven = new BreadOven();
BreadSingletonTwo.instance = this;
}

return BreadSingletonTwo.instance;
}

bake_bread(quantity, name) {
return this._oven.bake_bread(quantity, name);
}
put_on_shelf() {
return this._oven.put_on_shelf();
}
}

const oven = new BreadSingletonTwo();
Object.freeze(oven);
export default oven;=======================>import oven from "./Oven"oven.bake_bread(10, "ciabatta");
oven.put_on_shelf();

That’s so much of it! Happy Reading!

Hi :)