Kotlin Code Smell 23 - Singletons
One Too Many: The Slippery Slope of Singleton Patterns
Table of contents
Problem
Testability
Accidental implementation problems
Multi-threading issues
Static methods polluting
Object creation contract violation
Bijection mismatch
Memory issues
Premature Optimization
Solution
Avoid singletons altogether.
Use contextual unique objects instead of relying on a global instance.
Benchmark object creation to ensure performance is not adversely affected.
Examples
Database Access
Globals
Loggers
Helper classes
Sample Code
Wrong
// God is the archetypal singleton example
class God {
// In Kotlin, the companion object is always a singleton
companion object {
private var instance: God? = null
fun getInstance(): God {
if (instance == null) {
instance = God()
}
return requireNotNull(instance)
}
}
}
// Why should we be aware of getInstance when creating an object?
val jewishGod = God.getInstance()
Right
interface Religion {
// Define behavior
}
class God {
// There can be as many as you wish
}
class PolytheisticReligion(private val gods: Collection<God>) : Religion
class MonotheisticReligion(private val godAllMighty: God) : Religion
// According to Judaism, there's only one God,
// but this does not hold in other religions.
// Under this context, God is unique. We cannot create or change
// a new one.
val jewishGod = God()
val judaism = MonotheisticReligion(jewishGod)
val jupiter = God()
val saturn = God()
val mythologicalReligion = PolytheisticReligion(listOf(jupiter, saturn))
// Gods are unique (or not) according to context.
// We can create test religions with or without unicity.
// This is less coupled since we break the direct reference to the
// God class.
// The God class has the single responsibility to create gods, not
// to manage them.
Conclusion
The use of singletons is a historical mistake that has already been acknowledged by the community. Nevertheless, lazy developers bring it up again and again. We need to reach a consensus on its drawbacks and strive for better design patterns.