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) :
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.
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 . . 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 , . , . , - , . ?
. , 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
.
?
.
.
.
?
-
.
Golang. , .
mock-. , . dummy.
Singleton — , , . , , , . - — Singleton, . (SRP), , . Singleton, . Singleton — , .
, , . - -, , .
. Golang. .
Alex Versus. !