Hi friends.
My name is Alex Versus and today we will take a look at the Singleton pattern , an implementation in the Golang language .
What's the point?
Singleton - refers to generative patterns. Guaranteed:
that the class / type only has one instance
provides a global access point to it.
What problem does it solve?
Let's talk about the problem that the template solves. A loner solves two problems at once, violating the Single Responsibility Principle (SRP) :
Ensures that there is a single instance of the object. This is useful for accessing a shared resource, such as a database, or when implementing a single mechanism for changing a property, such as the sound level in an equalizer.
Let's imagine that we have some kind of object and after a while you create another one, but you would like to receive not a new, but already created object. This behavior cannot be created using standard tools such as the constructor in object-oriented languages.
Provide a global hotspot. Please note that this is not just a global variable through which you can reach a specific object. The global variable does not protect you from overwriting the created object.
, , . .
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. !