Salut les amis.
Je m'appelle Alex Versus et aujourd'hui nous allons jeter un œil au pattern Singleton , une implémentation dans le langage Golang .
À quoi ça sert?
Singleton - fait référence aux modèles génératifs. Garanti:
que la classe / le type n'a qu'une seule instance
lui fournit un point d'accès global.
Quel problème résout-il?
Parlons du problème que le modèle résout. Un solitaire résout deux problèmes à la fois, violant le principe de responsabilité unique (SRP) :
Garantit qu'il existe une seule instance de l'objet. Ceci est utile pour accéder à une ressource partagée, telle qu'une base de données, ou lors de l'implémentation d'un mécanisme unique pour modifier une propriété, comme le niveau sonore dans un égaliseur.
Imaginons que nous ayons une sorte d'objet et que vous en créez un autre après un certain temps, mais que vous aimeriez recevoir non pas un objet nouveau, mais déjà créé. Ce comportement ne peut pas être créé à l'aide d'outils standard tels que le constructeur dans les langages orientés objet.
Fournissez un hotspot mondial. Veuillez noter qu'il ne s'agit pas simplement d'une variable globale à travers laquelle vous pouvez atteindre un objet spécifique. La variable globale ne vous protège pas contre l'écrasement de l'objet créé.
Les développeurs appellent souvent des objets Lonely qui n'effectuent qu'une seule tâche, comme indiqué ci-dessus. C'est un malentendu du modèle.
Quelle est la solution à 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. !