w3resource

Kotlin Singleton Pattern: Implementing a logger for logging functionality


Write a Kotlin object-oriented program that implements a singleton pattern for a class Logger to provide logging functionality throughout the application.


Pre-Knowledge (Before You Start!)

Before attempting this exercise, you should be familiar with the following concepts:

  • Singleton Pattern: Understanding the singleton design pattern and its purpose in ensuring a single instance of a class.
  • Companion Objects: Using companion objects to define static-like behavior in Kotlin classes.
  • Thread Safety: Implementing a thread-safe singleton using synchronized blocks.
  • Logging Mechanism: Creating a logger class that can be accessed from different parts of an application.

Hints (Try Before Looking at the Solution!)

Try to solve the problem using these hints:

  • Hint 1: Define a private constructor in the Logger class to prevent direct instantiation.
  • Hint 2: Use a companion object to hold a single instance of the Logger class.
  • Hint 3: Implement a function getInstance() that ensures only one instance is created.
  • Hint 4: Use the synchronized block to make the singleton thread-safe.
  • Hint 5: In the main() function, get two instances of Logger and check if they are the same.

Sample Solution:

Kotlin Code:

class Logger private constructor() {
    init {
        println("Logger initialized")
    }

    fun log(message: String) {
        println("Logging: $message")
    }

    companion object {
        private var instance: Logger? = null

        fun getInstance(): Logger {
            if (instance == null) {
                synchronized(Logger::class.java) {
                    if (instance == null) {
                        instance = Logger()
                    }
                }
            }
            return instance!!
        }
    }
}

fun main() {
    val logger1 = Logger.getInstance()
    val logger2 = Logger.getInstance()

    logger1.log("Log message-1")
    logger2.log("Log message-2")

    println(logger1 === logger2) // true
}

Sample Output:

Logger initialized
Logging: Log message-1
Logging: Log message-2
true 

Explanation:

In the above exercise -

  • The "Logger" class has a private constructor to prevent direct instantiation. The class also has a log() method to simulate logging functionality.
  • Inside the Logger class, there is a companion object that holds reference to the single instance of the Logger class. The getInstance() method creates and returns an instance. It follows the double-checked locking approach to ensure thread safety.
  • In the "main()" function, we demonstrate the singleton pattern by creating two Logger instances using getInstance(). Both instances are the same because the Logger class ensures only one instance is created. The log() method is then called on both instances to simulate logging.
  • Finally, we compare logger1 and logger2 references using the === operator, which returns true since they are referencing the same object.

Kotlin Editor:


Previous: Shape base class and Polymorphic subclasses.
Next: Handling operation results.

What is the difficulty level of this exercise?

Test your Programming skills with w3resource's quiz.



Follow us on Facebook and Twitter for latest update.