In this tutorial, we will cover the singleton design pattern. This pattern is one of the most used and understood patterns in nowadays software. Kotlin provides some interesting native features to create and control singleton objects. With examples, we will show you how to create Kotlin singletons with parameters and with constructors.
The Gang Of Four described this pattern with the following words.
Ensure a class only has one instance, and provide a global point of access to it.
Design Patterns, Singleton Pattern
What is a singleton?
Before we start diving into the implementation details we will shortly discuss the singleton pattern and its usages. This pattern ensures that a class has only one instance and provides a global point of access to it.
The good point of this pattern is, that it allows easy access to the object and you don’t need to think about the lifetime of the object. The negative part is that is difficult to implement it “right” in multithreading programs and it makes testing / mocking much more difficult. Especially the last point is the reason why many people see this pattern actually as an “anti-pattern”. You could fake the singleton pattern by using a dependency injection framework.
A common use case of the pattern is, for example, a globally accessible configuration class. In our example, however, we will use a bit more sophisticated use case. It has some similarities to the Borg Pattern.
When to use a singleton?
An interesting discussion is in going in StackOverflow. It gives some good insights when to use this design pattern.
https://stackoverflow.com/questions/228164/on-design-patterns-when-should-i-use-the-singleton
They point out, that probably the “Logger Example” is one of the few examples which satisfies completely this design pattern.
Example
A common use case is when you’re having a database in your application. Often you need to control the access to this database (e.g. threading concerns). You can do that by providing the final access point. In our singleton example, we will provide a class called Storage. This class will work on SqlQuery objects. Every client (e.g. class Person), needs to create and configure a SqlQuery object and invoke the function execute of the Storage class. To illustrate the current setup we have created a simple UML diagramm.
Object / Companion Object
What is a singleton in Kotlin? Is Kotlin object a singleton?
The Kotlin language provides some features called Object or in combination with a class Companion Object. These declarations are designed to implement the Singleton class in Kotlin in a native way. One thing to mention is that objects are constructed in a lazy way. Also, they are never destroyed as they are available for the lifetime of the application.
How do I use a singleton in Kotlin?
As described in the above example we will implement the central access point with the class Storage. It is declared as an Object and can therefore be accessed globally in the codebase. It has one function “execute” which works with the SqlQuery objects. Within this function, the actual database access is happening.
Also, additional logic, such as queuing or thread-safe access might be implemented there. On the other hand, there is the class Person, which implements the interface Persistable. It creates a SqlQuery object and sets the desired SQL query (here not shown). One can imagine several different classes which implement the Persistable interface. All they need to do is to set the correct SqlQuery object and call at the end the Storage object.
object Storage { fun execute(query : SqlQuery) { } } class SqlQuery { } interface Persistable { fun persist() } class Person : Persistable { override fun persist() { val query = SqlQuery() Storage.execute(query) } } fun main() { val person = Person() person.persist() }
A Kotlin Object can also be used within a class. In this case, it is called Companion Object. It acts in a way like a inner class. This is useful if only some parts of the class are static. A slightly different implementation of the above example is the following code. The storage class is not any more static. Only its function “execute” is statically accessible. Note that the “execute” function can be accessed in the same syntactical way as before. The advantage of using a companion object to implement a singleton is that it allows using of inheritance.
class Storage { companion object { fun execute(query : SqlQuery) { } } } class Person : Persistable { override fun persist() { val query = SqlQuery() Storage.execute(query) } }
Kotlin Singleton Class with Constructor / Initialization
In Kotlin the Object has a init block like other classes. However, it does not provide a constructor. In general, we don’t need a specialized constructor, because the clients should not be in charge of the construction. But it might be useful to set some configurations before the singleton is initialized. In our example, we could imagine that the database is encrypted. The Storage class needs the password in order to open it when created the first time.
So how do you pass constructor arguments or parameters to a singleton in Kotlin?
Kotlin Singleton Class With Parameters
To implement parameters we need a normal class, having a companion object and private default constructors.
In the following implementation, the Storage class has a private constructor. So it can not be instantiated by any client. It needs a Config object, which contains all parameters / arguments to set up the storage. The companion object provides a getInstance method, which is creating the singleton object. This method accepts an optional configuration that is used the first time the static object is created. As you can see the Person object can call the Storage class in the same way (if it does not need to pass a parameter).
We want to highlight, that in general, this approach is not the best practice. We can not control who is going to call the first time the Storage class and since all subsequent calls are not using the config object, it is difficult to control well the configuration.
data class Config(val param: Int = 0) class Storage private constructor(private val config: Config) { companion object { private var instance : Storage? = null fun getInstance(config: Config = Config()): Storage { if (instance == null) // NOT thread safe! instance = Storage(config) return instance!! } fun execute(query: SqlQuery) { getInstance().execute(query) } } fun execute(query: SqlQuery) { } } class Person : Persistable { override fun persist() { val query = SqlQuery() Storage.execute(query) } }
In our opinion, it is better to create a separate function instead of a constructor to configure a singleton. With a separate function, we can better control the correct configuration and also is more thread-safe. A possible implementation could look like the following code.
object Storage { private val config = Config() fun configure(config : Config) { } fun execute(query: SqlQuery) { } }
Lazy
Usually, objects themself are already instantiated in a lazy way. So only on the first call, they will require memory. But we can even make the member variables lazy instantiated by adding the lazy keyword. If you want to learn more about Kotlin’s property delegation, have a look at our Delegation tutorial.
object Storage { private val heavyData: Int by lazy() { 5 } fun execute(query : SqlQuery) { println("Storage execute") } }
Thread-Safety
Is singleton thread-safe in Kotlin?
The reference page of Kotlin (LINK) states that “the initialization of an object declaration is thread-safe and done on first access”.
Access from Java
Kotlin and Java can be mixed within the codebase. So it is possible to use a Kotlin Singleton Object in Java and vice versa. Kotlin automatically provides a static field called “INSTANCE” to which it can be referred in Java code. Our example above can be accessed in Java such as:
public class JavaMain { public static void main(String[] args) { SqlQuery query = new SqlQuery(); Storage.INSTANCE.execute(query); } }
Dependency Injection
One of the main disadvantages of using a singleton is the difficulty to test these classes which are using the singleton. The reason is that there is a tight coupling from the client to the implementation of the Kotlin Object.
How to test a singleton class in Kotlin?
If you´re using a normal class in function with a companion object it is possible to replace the actual object with an inherited version. We will change the Storage class so that it implements the interface of IStorage. A second implementation (called MockStorage) does as well implement this interface. The storage class itself has a private constructor and holds the public companion object. The used “instance” is of type IStorage and can therefore be replaced. The following UML diagram shows the relationship.
interface IStorage { fun execute(query: SqlQuery) } open class Storage private constructor(): IStorage{ companion object { private var instance : IStorage? = null fun getInstance(): IStorage { if (instance == null) // NOT thread safe! instance = Storage() return instance!! } fun setInstance(storage : IStorage) { instance = storage } fun execute(query: SqlQuery) { getInstance().execute(query) } } override fun execute(query: SqlQuery) { println("Default implementation") } } class MockStorage : IStorage { override fun execute(query: SqlQuery) { println("Mocked implementation") } } fun main() { val testStorage = MockStorage() Storage.setInstance(testStorage) val person = Person() person.persist() }
The advantage of this approach is that you´re in full control of the code and you’re not dependent on any other library. The disadvantage however is you need to make sure that the threaded access is fully guaranteed to be safe.
KODEIN – Kotlin Dependency Injection Framework
KODEIN is a very useful dependency injection / retrieval container, it is very easy to use and configure. It gives one level of abstraction around the objects you want to inject. It is totally recommended to check out this library as it provides a good DSL language, and it is fast and optimized. Of course, you need to get used to this library and you need to deal with another dependency towards this one. In the end, most of your classes / modules will depend on this framework.
We have adapted our example so that the Person class needs a KODEIN object. This KODEIN object provides the dependency which can be retrieved / mapped by type. It is nice to see that we can now completely decouple objects from their dependencies.
open class Storage { open fun execute(query : SqlQuery) { println("Storage execute") } } class MockStorage : Storage() { override fun execute(query : SqlQuery) { println("MockStorage execute") } } class Person(val kodein: Kodein) : Persistable { private val storage by kodein.instance<Storage>() override fun persist() { val query = SqlQuery() storage.execute(query) } } fun main() { val kodein = Kodein { bind<Storage>() with singleton { MockStorage() } } val person = Person(kodein) person.persist() }
Android App Development
In most applications, there will be some classes that are the entry point of the code. In frontend-based applications, such as desktop, iOS, or Android applications, there will be a class that holds all the view models, gateways, etc.
Application Class
One of those classes is the Application class. Typically the application class is the most basic class in your cold. It holds general business logic and glue code. It can be that it is the provider for factories (e.g. Abstract Factory Method), gateways to servers and databases, and main access point to view models and controllers. It is the base class for maintaining global application state.
Specific to Android, such application class holds as well all activities and services.
As this class holds very global information it makes sense to provide singleton access to the application class in Android.
ViewModel
Usually, ViewModels should not be singleton objects. They provide dynamic data and are bound to the context of an Activity or Fragment.
Code Completion / Syntax Highlighting in IDEs
Most IDEs do support the Kotlins native capabilities like the Object and Companion object keyword. As you can see in the following images, Jetbrains Intellij shows correctly the Object Class.