"If a worker wants to do his job well, he must first sharpen his tools." - Confucius, "The Analects of Confucius. Lu Linggong"
Front page > Programming > Singleton Design Pattern

Singleton Design Pattern

Published on 2024-07-30
Browse:775

Singleton Design Pattern

The Singleton design pattern is one of the most important and frequently used in software programming. It ensures that a class has only a single instance during application runtime and provides a global access point to that instance. In this article, we will discuss the importance of Singleton, how to implement it in Golang, and the benefits it brings, especially in concurrent environments.

What is Singleton?

Singleton is a design pattern that restricts the instance of a class to a single instance. It is particularly useful in situations where a single point of control or a single shared resource is required, such as:

  • Configuration managers, where application settings need to be centralized.
  • Database connection pools, where a limited number of connections must be managed efficiently.
  • Loggers, where log consistency is crucial.

Why use Singleton?

I'm going to list some points about the implementation from Pattern that make more sense and also to show that not everything is rosy, some of the problems we can have with it.

Benefits

  • Global Consistency: Guarantees that all points of the application use the same instance, providing data and behavior consistency.
  • Access Control: Centralizes control of creation and access to the instance, facilitating maintenance and management of the object's life cycle.
  • Resource Efficiency: Avoids the unnecessary creation of multiple instances, saving memory and processing resources.

Disadvantages

  • Test Difficulty: Singletons can make writing unit tests more difficult because they introduce global states that need to be managed.
  • Increased Coupling: Excessive use of Singletons can lead to tighter coupling between components, making it difficult to maintain and evolve the application.

Implementing a Singleton

To implement a singleton I will use Golang. In this language we have to pay special attention to concurrency to ensure that only one instance is created, even when multiple goroutines try to access the instance simultaneously.

To bring our example closer to the real world, let's create a Logger for our application. A logger is a common tool in applications that needs to be unique to ensure log consistency.

1 - Defining the structure

First, we define the structure that we want to have a single instance.

package logger

import (
    "fmt"
    "sync"
)

type Logger struct {}

var loggerInstance *Logger

2 - Implementing the NewInstance function

The NewInstance function is responsible for returning the single instance of the Singleton structure. We use a mutex to ensure security in concurrent environments, implementing double-checked locking for efficiency.

package logger

import (
    "fmt"
    "sync"
)

type Logger struct{}

var logger *Logger
var mtx = &sync.Mutex{}

func NewInstance() *Logger {
    if logger == nil {
        mtx.Lock()
        defer mtx.Unlock()
        if logger == nil {
            fmt.Println("Creating new Logger")
            logger = &Logger{}
        }
    } else {
        fmt.Println("Logger already created")
    }
    return logger
}

3 - Implementing log types

A Log tool always has some log types, such as Info to just show the information, Error to show errors and so on. It's a way to also filter the type of information we want to show in our application.

So let's create a method that will show our log with the Info type. To do this we will create a function that will receive our log message and format it to INFO format.

package logger

import (
    "fmt"
    "sync"
    "time"
)

const (
    INFO    string = "INFO"
)

type Logger struct{}

var logger *Logger
var mtx = &sync.Mutex{}

func NewInstance() *Logger {
    if logger == nil {
        mtx.Lock()
        defer mtx.Unlock()
        if logger == nil {
            fmt.Println("Creating new logger")
            logger = &Logger{}
        }
    } else {
        fmt.Println("Logger already created")
    }
    return logger
}

func (l *Logger) Info(message string) {
    fmt.Printf("%s - %s: %s\n", time.Now().UTC().Format(time.RFC3339Nano), INFO, message)
}

4 - Using the Logger

And to use our new logger, we will instantiate it within our main package and create a log to see how this implementation works.

package main

import (
    "playground-go/pkg/logger"
)

func main() {
    log := logger.NewInstance()
    log.Info("This is an example of log")
}

This is the result when we run the program:

Creating new logger
2024-07-03T19:34:57.609599Z - INFO: This is an example of log

If we want to test whether NewInstance is really guaranteeing that we will only have one instance running, we can do the following test.

package main

import (
    "fmt"
    "playground-go/pkg/logger"
)

func main() {
    log := logger.NewInstance()
    log.Info("This is an example of log")

    log2 := logger.NewInstance()
    log2.Info("This is another example of log")

    if log == log2 {
        fmt.Println("same instance")
    } else {
        fmt.Println("different instance")
    }
}

Our logs have changed and now we can see that we blocked the creation of a new instance:

Creating new logger
2024-07-03T19:45:19.603783Z - INFO: This is an example of log
Logger already created
2024-07-03T19:45:19.603793Z - INFO: This is another example of log
same instance

Conclusion

The Singleton pattern is a powerful tool for ensuring that only one instance of a specific class exists during application runtime. In the logger example, we saw how this pattern can be applied to ensure log consistency across the application.

Hope this helps you understand Singleton in Golang better.

Release Statement This article is reproduced at: https://dev.to/rflpazini/singleton-design-pattern-1n51?1 If there is any infringement, please contact [email protected] to delete it
Latest tutorial More>

Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.

Copyright© 2022 湘ICP备2022001581号-3