DEV Community

Oluwasanmi Aderibigbe
Oluwasanmi Aderibigbe

Posted on • Updated on

Head First Design Pattern: 4 of 10

I just learnt my fourth design from the Head First Design Pattern book. Today, I learnt about the Singleton pattern.

According to Head First Design Patterns, the Singleton pattern is a pattern that is used to ensure a class has only one instance, and provides a global point of access to it.

For example, the singleton pattern can be implemented in Java like this

public class Singleton {
    private static Singleton instance;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
Enter fullscreen mode Exit fullscreen mode

In order to ensure the Singleton class only has one instance, It's constructor is marked as private. Singleton has an API called getInstance().

The Singleton pattern seems like a very simple pattern but there are some gotchas you need to be aware of when it comes to using the Singleton pattern and multithreading. In a multithreaded code, it is possible to create multiple instances of the class above since multiple thread can have access to the getInstance function at the same time.
There are many ways to fix this:

1: Refactor the code above to use synchronised keyword.

public class Singleton {
    private volatile static Singleton instance;

    private Singleton() {
    }

    public static synchronised Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
Enter fullscreen mode Exit fullscreen mode

By adding the synchronised keyboard to the getInstance() we are forcing every thread to wait it's turn before they enter the function. So only one thread can access the getInstance() function.

2: Simply use the Object keyword from Kotlin. Kotlin has the Singleton pattern built into the language with the Object keyword.

object Singleton {
}
Enter fullscreen mode Exit fullscreen mode

If you need to have on instance of a class, for example, loggers, analytics, crash reporting. You should use the Singleton pattern

Discussion (7)

Collapse
ddaypunk profile image
Andy Delso

For Selenium in Java I was using a singleton pattern to setup the WebDriver instance. Since switching to Kotlin, I was having issues with it working reliably with the object way. I was getting multiple browsers opened, which is contrary to the singleton pattern purpose.

How are you using this pattern with or without the object concept in Android?

Collapse
jeehut profile image
Cihat Gündüz

Could it be that your code was getting called multiple times or in multiple threads? I'm not sure but I can imagine that with Selenium. You might want to search for "thread-safe singleton" in Kotlin when trying to fix it again, quite possible the object approach isn't by default, but I'm sure there's an easy fix.

Collapse
sanmiade profile image
Oluwasanmi Aderibigbe Author

That makes a lot of sense. Thanks Cihat for the explanation. Although, kotlin object is actually thread safe. kotlinlang.org/docs/object-declara...

Thread Thread
ddaypunk profile image
Andy Delso

That is what I thought, but if it is spinning up multiple threads, maybe that is why it is spinning up multiple browser instances. I’ll have to look into it again when I get time away from Android studies lol.

Collapse
ddaypunk profile image
Andy Delso

Ah that is a good point to make. It is possible I set it up with parallel running without thinking about it! Will do and thanks for the tip!

Collapse
sanmiade profile image
Oluwasanmi Aderibigbe Author • Edited on

Oh, That's very weird. I don't know anything about Selenium. I've always used the object keyword whenever I need to use the Singleton pattern but you can try this. It should work.

fun main() {
    val signleton = ManualSignleton.getInstance()
}

class ManualSignleton {
    private constructor()

    companion object {
        @Volatile
        private var INSTANCE: ManualSignleton? = null

        fun getInstance(): ManualSignleton {
            return INSTANCE ?: synchronized(this) {
                val newInstance = ManualSignleton()
                INSTANCE = newInstance
                newInstance
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Let me know if it does

Collapse
ddaypunk profile image
Andy Delso

If and when I get back to the project, I can try it! Thanks!