"Si un trabajador quiere hacer bien su trabajo, primero debe afilar sus herramientas." - Confucio, "Las Analectas de Confucio. Lu Linggong"
Página delantera > Programación > Patrón de diseño singleton

Patrón de diseño singleton

Publicado el 2024-07-30
Navegar:327

Singleton Design Pattern

El patrón de diseño Singleton es uno de los más importantes y utilizados con frecuencia en la programación de software. Garantiza que una clase tenga una sola instancia durante el tiempo de ejecución de la aplicación y proporciona un punto de acceso global a esa instancia. En este artículo, analizaremos la importancia de Singleton, cómo implementarlo en Golang y los beneficios que aporta, especialmente en entornos concurrentes.

¿Qué es Singleton?

Singleton es un patrón de diseño que restringe la instancia de una clase a una sola instancia. Es particularmente útil en situaciones donde se requiere un único punto de control o un único recurso compartido, como por ejemplo:

  • Administradores de configuración, donde es necesario centralizar la configuración de la aplicación.
  • Grupos de conexiones de bases de datos, donde se debe administrar de manera eficiente un número limitado de conexiones.
  • Registradores, donde la coherencia de los registros es crucial.

¿Por qué utilizar Singleton?

Voy a enumerar algunos puntos sobre la implementación de Pattern que tienen más sentido y también para mostrar que no todo es color de rosa, algunos de los problemas que podemos tener con ello.

Beneficios

  • Consistencia global: Garantiza que todos los puntos de la aplicación utilicen la misma instancia, proporcionando coherencia en los datos y el comportamiento.
  • Control de Acceso: Centraliza el control de creación y acceso a la instancia, facilitando el mantenimiento y gestión del ciclo de vida del objeto.
  • Eficiencia de recursos: Evita la creación innecesaria de múltiples instancias, ahorrando memoria y recursos de procesamiento.

Desventajas

  • Dificultad de la prueba: los singleton pueden dificultar la redacción de pruebas unitarias porque introducen estados globales que deben gestionarse.
  • Aumento del acoplamiento: el uso excesivo de Singletons puede provocar un acoplamiento más estrecho entre los componentes, lo que dificulta el mantenimiento y la evolución de la aplicación.

Implementando un singleton

Para implementar un singleton usaré Golang. En este lenguaje tenemos que prestar especial atención a la concurrencia para garantizar que solo se cree una instancia, incluso cuando varias gorutinas intentan acceder a la instancia simultáneamente.

Para acercar nuestro ejemplo al mundo real, creemos un registrador para nuestra aplicación. Un registrador es una herramienta común en aplicaciones que debe ser única para garantizar la coherencia del registro.

1 - Definición de la estructura

Primero, definimos la estructura que queremos que tenga una sola instancia.

package logger

import (
    "fmt"
    "sync"
)

type Logger struct {}

var loggerInstance *Logger

2 - Implementación de la función NewInstance

La función NewInstance es responsable de devolver la instancia única de la estructura Singleton. Usamos un mutex para garantizar la seguridad en entornos concurrentes, implementando un bloqueo de doble verificación para mayor eficiencia.

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 - Implementación de tipos de registros

Una herramienta de registro siempre tiene algunos tipos de registro, como Información para mostrar solo la información, Error para mostrar errores, etc. Es una forma de filtrar también el tipo de información que queremos mostrar en nuestra aplicación.

Entonces, creemos un método que mostrará nuestro registro con el tipo de información. Para hacer esto, crearemos una función que recibirá nuestro mensaje de registro y lo formateará en formato INFO.

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 - Usando el registrador

Y para usar nuestro nuevo registrador, crearemos una instancia dentro de nuestro paquete principal y crearemos un registro para ver cómo funciona esta implementación.

package main

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

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

Este es el resultado cuando ejecutamos el programa:

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

Si queremos probar si NewInstance realmente garantiza que solo tendremos una instancia ejecutándose, podemos hacer la siguiente prueba.

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")
    }
}

Nuestros registros han cambiado y ahora podemos ver que bloqueamos la creación de una nueva instancia:

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

Conclusión

El patrón Singleton es una herramienta poderosa para garantizar que solo exista una instancia de una clase específica durante el tiempo de ejecución de la aplicación. En el ejemplo del registrador, vimos cómo se puede aplicar este patrón para garantizar la coherencia del registro en toda la aplicación.

Espero que esto te ayude a comprender mejor Singleton en Golang.

Declaración de liberación Este artículo se reproduce en: https://dev.to/rflpazini/singleton-design-pattern-1n51?1 Si hay alguna infracción, comuníquese con [email protected] para eliminarla.
Último tutorial Más>

Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.

Copyright© 2022 湘ICP备2022001581号-3