According to the design rules, a singleton pattern must exist in an instance. If I remove the line of code and return an object, will the function be a single pattern?
const singleton = (function(){
let instance,
counter = 0;
const createInstance = () => ({
getCounter: () => counter,
addCounter: (num) => counter += num,
})
return {
getInsctance: () => createInstance() // insctance || (insctance = createInsctance()) ????
}
})()
const r = singleton.getInsctance()
const r2 = singleton.getInsctance()
r.addCounter(12)
r2.addCounter(32)
singleton.counter = 100
console.log(r2.getCounter()) // 44
console.log(r.getCounter()) // 44
Why is this feature not singleton pattern?
2
Answers
The definition of the Singleton design pattern is that there will only be one instance of the class. Whenever you call the constructor, it should return the same instance. This is typically implemented by creating a new instance the first time the constructor is called, and saving that instance in a variable so that future calls can return it.
In your code this is what the
instance
variable is for. The first time you callsingleton.getInstance()
, the variable is undefined, so the||
logical operator returns the value of the second expression. This callscreateInstance()
, which creates a new object. It saves this ininstance
and returns it.Your code acts like a singleton because you’re not actually storing any data in the instances. You’re keeping the counter value in a closure variable that’s shared by all instances.
To make a true singleton, you should move
counter
into a property of the object that’s returned bycreateInstance()
, and usethis.counter
in the other methods. Note that for this to work the methods must be traditional functions rather than arrow functions, because arrow functions don’t receivethis
from the method call.The next time you call
singleton.getInstance()
, the variableinstance
contains that object. So the logical||
operator returns that value.Assigning to
singleton.counter
has no effect in either version of the code. In your version,counter
is a local variable; this is not the same as a property of the object that the IIFE returns. In my version,counter
is a property of the instance returned bycreateInstance()
, which is not the same assingleton
itself.Note that counters are not a good use of the Singleton pattern. Usually you need to create multiple counters, each keeping track of their own sequence of values.
Singleton is a pattern that means that the class/function cannot be a singleton unless there cannot be two instances of it at the same time.
A nice implementation of the singleton pattern can be seen here https://www.dofactory.com/javascript/design-patterns/singleton
From the outside you cannot call
createInstance
, that is, to protect the pattern and you can callgetInstance
.Since the requirement of the singleton pattern is to not have more than one instance, you can have 0 instance and you can destroy an object and create another. But you will need to make sure that at all times there will be no more than one instance of that class/function.
Your code is not following the singleton pattern, because, from the outside it can be instantiated even when it’s already instantiated:
Let’s make it a singleton:
Here I’m reusing the instance instead of creating it if it was already existent.