Singleton / Multiton Design Pattern

The singleton and multiton design patterns are described in the section of creational software patterns in the book of the Gang-Of-Four. In general this pattern restricts the instantiating of a class to one single instance. The multiton design pattern is a generalization of the singleton. In the following we are going to talk about how singletons and multitons can be implemented in Kotlin by giving several examples and use cases. Afterwards we discuss how the difficulty in testing such singletons can be solved.

The singleton and multiton design pattern focuses on the following questions:

  • How can it be ensured that a class has only one instance?
  • How can the sole instance of a class be accessed easily?
  • How can a class control its instantiation?
  • How can the number of instances of a class be restricted?

One additional point which has to be considered is thread safety of Singletons / Multitons.

Singleton Pattern

In general singletons are realized by hiding the constructor from a class and providing a static access function. This static access function (e.g. getInstance) is in charge to create this single object and returns always the same object. In Kotlin static methods do not exist, thus this approach can not be taken.

Kotlin has a special keyword (“object“) which can be used instead of the class keyword. This keyword will take care, that only one instance of this class is created. As you can see, a singleton in Kotlin is fairly easy.

In our example scenario we are considering a printer within a network. Lets assume that there is only one (“physical”) printer in your network and you want to control the instantiation of this class. Therefore, it makes sense to make the printer a singleton.

Printer Singleton object

object Printer{
    val randomNumber = (1..100).shuffled().first()
    fun print(){
        println("Print page from printer: $randomNumber")
    }
}

The printer singleton has a randon number as member variable. The reason fort his random number is to show that there is only one object of the printer class.

Usage of Singleton object

fun main(){
    var printer1 = Printer
    var printer2 = Printer

    printer1.print()
    printer2.print()

    println(printer1 == printer2)
    println(printer1 === printer2)
}

When you run this code you will see, that both printer1 and printer2 variable are refering to the same object. Note that the random numbers are equal.

Multiton Pattern

The singleton pattern can be generalized to the multiton (or flyweight) pattern. Now imagine the case that there are several printers in the network. Each printer can be identified with the internal id. One way to assure to have only one object per individual printer is to use a companion object within the printer class. This companion object (a singleton itself) has a map from printer ID to printer object. It is in charge to provide the printer from the map via the getPrinter function. To make this work we need to make the printer constructor private, while the companion object has still access to the constructor.

class Printer private constructor(var id : Int){
    val randomNumber = (1..100).shuffled().first()

    companion object AvailablePrinter{
        private var availablePrinter = mutableMapOf<Int, Printer>()

        fun getPrinter(id : Int) : Printer {
            val printer = availablePrinter[id]
            if(printer == null){
                availablePrinter[id] = Printer(id)
            }
            return availablePrinter[id]!!
        }
    }

    fun print(){
        println("Print page from printer: $randomNumber")
    }
}

Multiton with different subclasses

We can even go a step further and imagine different kind of printers in the same network. These printers are still unique and can be identified with their ID. In our example we are having two kinds of printers: ClientPrinter and TablePrinter. The difference between them is not important, but they are two distinct classes which implement the IPrinter interface.

IPrinter Interface and derived classes

interface IPrinter{
    val randomNumber : Int
    fun print()
}

class ClientPrinter : IPrinter{
    override val randomNumber = (1..100).shuffled().first()
    override fun print() {
        println("Print page from client printer: $randomNumber")
    }
}

class TablePrinter : IPrinter{
    override val randomNumber = (1..100).shuffled().first()
    override fun print() {
        println("Print page from table printer: $randomNumber")
    }
}

The printers will be hosted in the PrinterHost class, which is designed to be a singleton. This class provides functions to get the printer by id for the unchecked type version (IPrinter) and the checked type version (with generic template). Notice that in this setup the printer needs to be manually registered so that they can be found. The reason is that no objects from a generic class can be instantiated within the function, without providing a factory method.

PrinterHost class

object PrinterHost{
    private var availablePrinter = mutableMapOf<Int, IPrinter>()

    fun <TType>registerPrinter(id: Int, printer : TType)
            where TType : IPrinter
    {
        availablePrinter[id] = printer
    }

    fun <TType>getTypedPrinter(id : Int) : TType{
        return getPrinter(id)!! as TType
    }

    fun getPrinter(id : Int) : IPrinter{
        val printer = availablePrinter[id]

        if(printer == null){
            // handle somehow this case
        }

        return printer!!
    }
}

How to test singletons / multitons in Kotlin?

The biggest problem with singletons is that they make testing difficult. The reason is that they can usually not mocked and therefore their behaviour not be altered. For singletons which behaviour is easy to predict, this may not be a big problem. Consider however the case where a singleton is the access point of a remote server. This will be impossible to test in a adequate manner. This is the reason why the singleton is often considered as an anti-pattern. Luckely some solution exist which help to test your code.

Using Strategy pattern

In this example we are considering again the printer class. Again this class is a singleton.

Original Printer class

object Printer{
    fun print(){
        println("Print page from printer.")
    }
}

The printer object implements now an interface IPrinter and has aswell a variable which represents the implementation strategy. This strategy implements the same IPrinter interface. The function calls from the printer class are redirected towards the strategy method.

Printer Interface and Printer Object implementation

interface IPrinter {
    fun print()
}

object Printer : IPrinter{
    private lateinit var impl : IPrinter

    fun setImplementation(impl : IPrinter){
        this.impl = impl
    }

    override fun print(){
        impl.print()
    }
}

Printer Implementation Class and Mock Class

class PrinterImplementation : IPrinter {
    override fun print() {
        println("Print page from printer")
    }
}

class PrinterMock : IPrinter {
    override fun print() {
        println("Printer Mock page")
    }
}

Usage of mock implementation

Since this approach allows to change the strategy implementation dynamically during run time, the tester can replace the printer with a mock object.

fun main(){
    Printer.setImplementation(PrinterImplementation())
    Printer.print()

    Printer.setImplementation(PrinterMock())
    Printer.print()
}
Singleton Test UML with Strategy Pattern

Using Delegates

A different option to use the strategy pattern is the use of Kotlins internal delegates structure. Kotlin provides a way (keyword by) to give a delegate to an object or class. The result is that the printer has now all functions which delegate implements. The advantage is that this approach basically does not create addtional or un- used code. For that reason this approach is better than the “normal” strategy pattern.

Printer Delegate Setup

var printerDelegate : IPrinter = PrinterImplementation()

object Printer : IPrinter by printerDelegate

Usage of Printer Delegate

fun main(){
    printerDelegate = PrinterMock()
    Printer.print()
}

Using Mocking Framework

A third alternative is to use a mocking framework. These frameworks give you the opportunity to test your singletons without using additional design patterns. The disadvantage however is that you have to put extra effort to integrate these frameworks.

If this is not a problem for you, we recommend that you check out one of the mocking frameworks which is out there:

Mockk – Mocking library for Kotlin

https://mockk.io/

Mockito – Kotlin

https://github.com/nhaarman/mockito-kotlin

Conclusion

We discussed how Kotlin integrates the singleton and multiton design pattern natively by using the “object” keyword. Kotlin provides build-in capabilities to create singletons. Due to difficulty to test these instances, we showed some ways to test your application. With the use of Kotlins build-in delegates system one can create singletons which are easy accessible and as well testable.