TL;DR: Ensure a class has only one instance and provide a global access point to it with the Singleton pattern, which is useful for coordinating actions across a system.
Intent
Ensure a class only has one instance, and provide a global point of access to it.
Explanation
Real-world example
There can only be one ivory tower where the wizards study their magic. The same enchanted ivory tower is always used by the wizards. The ivory tower here is a singleton.
In plain words
Ensures that only one object of a particular class is ever created.
Wikipedia says
In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.
Programmatic Example
Kotlin makes it externally easy to create singletons by introducing the language keyword object
. By using this keyword, we will get an implementation of the Singleton pattern from the compiler that contains all of our requirements.
data object IvoryTower
One of the key differences between a class
and a object
is that the latter does not allow constructor arguments. If your implementation needs initialization for your Singleton (e.g. to load data) you can use an init
block.
data object IvoryTower {
init {
logger.info("Initializing Ivory Tower...")
}
}
Note that if the Singleton object is never invoked, it won't run its initialization block at all. This is called lazy initialization.
Then in order to use:
val ivoryTower1 = IvoryTower
val ivoryTower2 = IvoryTower
logger.info("ivoryTower1={}", ivoryTower1)
logger.info("ivoryTower2={}", ivoryTower2)
The output on the console:
09:21:31.107 [main] INFO Singlton -- Initializing Ivory Tower...
09:21:31.109 [main] INFO Singlton -- ivoryTower1=com.yonatankarp.singleton.IvoryTower@1207938418
09:21:31.111 [main] INFO Singlton -- ivoryTower2=com.yonatankarp.singleton.IvoryTower@1207938418
Class diagram
Applicability
Use the Singleton pattern when
There must be exactly one instance of a class, and it must be accessible to clients from a well-known access point
When the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying their code
Some typical use cases for the Singleton
The logging class
Managing a connection to a database
File manager
Consequences
Violates the Single Responsibility Principle (SRP) by controlling their creation and lifecycle.
Encourages using a globally shared instance which prevents an object and resources used by this object from being deallocated.
Creates tightly coupled code. The clients of the Singleton become difficult to test.
It makes it almost impossible to subclass a Singleton.
I hope you enjoyed this journey and learned something new. If you want to stay updated with my latest thoughts and ideas, feel free to register for my newsletter. You can also find me on LinkedIn or Twitter. Let's stay connected and keep the conversation going!
Code Examples
All code examples and tests can be found in the Kotlin Design Patterns repository
Top comments (0)