Home  >  Article  >  Backend Development  >  Singleton Design Pattern

Singleton Design Pattern

王林
王林Original
2024-07-18 13:46:47899browse

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.

Advantages

  • 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 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.

I hope this helps you understand Singleton in Golang better.

The above is the detailed content of Singleton Design Pattern. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:Merge orted listsNext article:Merge orted lists