Las sutilezas de la implementación de Singleton en Golang

Hola amigos.





Mi nombre es Alex Versus y hoy veremos el patrón Singleton , una implementación en el lenguaje Golang .





¿Cuál es el punto de?

Singleton: se refiere a patrones generativos. Garantizado:





  • que la clase / tipo solo tiene una instancia





  • proporciona un punto de acceso global.





¿Qué problema soluciona?

Hablemos del problema que resuelve la plantilla. Un solitario resuelve dos problemas a la vez, violando el Principio de Responsabilidad Única (SRP) :





  1. Asegura que haya una única instancia del objeto. Esto es útil para acceder a un recurso compartido, como una base de datos, o cuando se implementa un mecanismo único para cambiar una propiedad, como el nivel de sonido en un ecualizador.

    Imaginemos que tenemos algún tipo de objeto y después de un tiempo creas otro, pero te gustaría recibir no un objeto nuevo, sino ya creado. Este comportamiento no se puede crear utilizando herramientas estándar como el constructor en lenguajes orientados a objetos.





  2. Proporcionar un punto de acceso global. Tenga en cuenta que esta no es solo una variable global a través de la cual puede llegar a un objeto específico. La variable global no lo protege de sobrescribir el objeto creado.





Los desarrolladores suelen llamar objetos Lonely que realizan una sola tarea, como se describe anteriormente. Este es un malentendido del patrón.





¿Cuál es la solución en Golang?

GOlang? , , , -. . . - . :





Diagrama de clases singleton
Singleton

GOlang . . getInstance()



? singleton



:





// declaration defined type 
type singleton struct {
   
}
      
      



singleton



, nil:





// declare variable
var instance *singleton = nil
      
      



instance



sync.Once



. , . Sigleton



:





// defined type with interface
type Singleton interface {
// here will be methods
}
      
      



:





// Get only one object
func GetInstance() Singleton {
   once.Do(func() {
      instance = new(singleton)
   })
   return instance
}
      
      



singleton



, :





// declaration defined type
type singleton struct {
   title string
}
      
      



Singleton



, :





// defined type with interface
type Singleton interface {
   SetTitle(t string)
   GetTitle() string
}


// Setter for singleton variable
func (s *singleton) SetTitle(t string) {
   s.title = t
}

// Getter singleton variable
func (s *singleton) GetTitle() string {
   return s.title
}
      
      



.





, . , :





package Singleton

import "testing"

func TestGetInstance(t *testing.T) {
   var s Singleton
   s = GetInstance()
   if s == nil {
      t.Fatalf("First sigletone is nil")
   }

   s.SetTitle("First value")
   checkTitle := s.GetTitle()

   if checkTitle != "First value" {
      t.Errorf("First value is not setted")
   }

   var s2 Singleton
   s2 = GetInstance()
   if s2 != s {
      t.Error("New instance different")
   }

   s2.SetTitle("New title")
   newTitle := s.GetTitle()
   if newTitle != "New title" {
      t.Errorf("Title different after change")
   }
}
      
      



:





go test -v -run TestGetInstance
=== RUN   TestGetInstance
--- PASS: TestGetInstance (0.00s)
PASS
ok      main/Singleton  0.310s
      
      



! , , . , , :





package Singleton

import (
   "fmt"
   "strconv"
   "sync"
   "testing"
)

func TestSecondGetInstance(t *testing.T) {
   s1 := GetInstance()
   s2 := GetInstance()

   var w sync.WaitGroup

   for i := 0; i < 3000; i++ {
      j := i
      w.Add(1)
      go func() {
         t := "title_" + strconv.Itoa(j)
         s1.SetTitle(t)
         w.Done()
      }()
      w.Add(1)
      go func() {


         t2 := "title_2_" + strconv.Itoa(j)
         s2.SetTitle(t2)
         w.Done()
      }()
   }

   fmt.Println(s1.GetTitle())
   fmt.Println(s2.GetTitle())
}
      
      



:





go test -v -run TestSecondGetInstance
=== RUN   TestSecondGetInstance
title_2998
title_2_2999
      
      



3000 , . , . , - , . ?





-ra



, . Golang, . .





. , Singleton. . , . , , : . , , . Go : sync.Mutex



sync.RWMutex



. :





// declaration defined type
type singleton struct {
   title string
   sync.RWMutex
}

// Setter for singleton variable
func (s *singleton) SetTitle(t string) {
   s.Lock()
   defer s.Unlock()
   s.title = t
}

// Getter singleton variable
func (s *singleton) GetTitle() string {
   s.RLock()
   defer s.RUnlock()
   return s.title
}
      
      



, :





go test -v -run TestSecondGetInstance
=== RUN   TestSecondGetInstance
--- PASS: TestSecondGetInstance (0.00s)
PASS
      
      



Singleton



Golang



.





?

  1. .





  2. .





  3. .





?

  1. . // , .





  2. .





  3. Golang. , .





  4. mock-. , . dummy.





Singleton — , , . , , , . - — Singleton, . (SRP), , . Singleton, . Singleton — , .





, , . - -, , .





. Golang. .

Alex Versus. !








All Articles