одноэлементный шаблон
Википедия: Одноэлементный шаблон, также известный как монадический шаблон, является широко используемым шаблоном проектирования программного обеспечения. При применении этого шаблона класс одноэлементного объекта должен гарантировать, что существует только один экземпляр. Во многих случаях всей системе требуется только один глобальный объект, который помогает нам координировать поведение системы в целом. Например, в серверной программе информация о конфигурации сервера хранится в файле, и данные конфигурации единообразно считываются одноэлементным объектом, а затем другие объекты в процессе обслуживания получают информацию о конфигурации через одноэлементный объект. Такой подход упрощает управление конфигурацией в сложных средах.
Эффект, который должен быть достигнут с помощью одноэлементного шаблона, состоит в том, что для класса, применяющего одноэлементный шаблон, во всей программе существует только один конкретизированный объект.
go не является объектно-ориентированным языком, поэтому вместо него мы используем структуры
Есть несколько способов:
-
ленивый режим
-
режим голодного человека
-
Механизм блокировки с двойной проверкой
Следующий раскол объясняет:
ленивый режим
- Создайте пример структуры
type example struct {
name string
}
- Установите приватную переменную в качестве синглтона, который будет возвращаться каждый раз
var instance *example
- Напишите метод, который может получить синглтон
func GetExample() *example {
// 存在线程安全问题,高并发时有可能创建多个对象
if instance == nil {
instance = new(example)
}
return instance
}
-
пройти тест
func main() { s := GetExample() s.name = "第一次赋值单例模式" fmt.Println(s.name) s2 := GetExample() fmt.Println(s2.name) }
В ленивом режиме существует проблема безопасности потоков. На шаге 3, если несколько потоков вызывают этот метод одновременно,
тогда его обнаружатinstance
заnil
, будет создано несколько объектов, поэтому появится голодный режим...
режим голодного человека
Подобно режиму ленивого человека, больше нечего сказать, перейдите непосредственно к коду
// 构建一个结构体,用来实例化单例
type example2 struct {
name string
}
// 声明一个私有变量,作为单例
var instance2 *example2
// init函数将在包初始化时执行,实例化单例
func init() {
instance2 = new(example2)
instance2.name = "初始化单例模式"
}
func GetInstance2() *example2 {
return instance2
}
func main() {
s := GetInstance2()
fmt.Println(s.name)
}
Голодный режим создаст одноэлементный объект при загрузке пакета.Когда объект не используется в программе, часть пространства тратится впустую
По сравнению с ленивым режимом он безопаснее, но замедляет скорость запуска программы.
механизм двойной проверки
В ленивом режиме есть проблема безопасности потоков, обычно мы используем мьютекс для решения проблемы несогласованности данных, которая может возникнуть.
Так что измените вышеGetInstance()
Методы, как показано ниже:
var mux Sync.Mutex
func GetInstance() *example {
mux.Lock()
defer mux.Unlock()
if instance == nil {
instance = &example{}
}
return instance
}
Если вы сделаете это, каждый раз, когда запрашивается синглтон, блокировка будет добавляться и разблокироваться, а использование блокировки — только для решения проблемы параллелизма, которая может возникнуть при инициализации объекта.
После создания объекта блокировка бессмысленна и замедляет скорость, поэтому вводим механизм двойной проверки (Check-lock-Check
),
Также известен какDCL
(Double Check Lock
), код показан ниже:
func GetInstance() *example {
if instance == nil { // 单例没被实例化,才会加锁
mux.Lock()
defer mux.Unlock()
if instance == nil { // 单例没被实例化才会创建
instance = &example{}
}
}
return instance
}
Таким образом, только когда объект не инициализирован, операции блокировки и разблокировки будут выполняться снова.
Но возникает другая проблема: каждый доступ нужно проверять дважды, чтобы решить эту проблему, мы можем использовать методы из стандартного пакета golang для атомарной операции:
import "sync"
import "sync/atomic"
var initialized uint32
func GetInstance() *example {
// 一次判断即可返回
if atomic.LoadUInt32(&initialized) == 1 {
return instance
}
mux.Lock()
defer mux.Unlock()
if initialized == 0 {
instance = &example{}
atomic.StoreUint32(&initialized, 1) // 原子装载
}
return instance
}
Приведенный выше код нужно обработать только один раз, чтобы вернуть синглтон, но стандартный пакет golang на самом деле предоставляет нам соответствующие методы:
sync.Once
изDo
Метод может понимать, что обратный вызов запускается только один раз во время работы программы, поэтому окончательный упрощенный код выглядит следующим образом:
type example3 struct {
name string
}
var instance3 *example3
var once sync.Once
func GetInstance3() *example3 {
once.Do(func() {
instance3 = new(example3)
instance3.name = "第一次赋值单例"
})
return instance3
}
func main() {
e1 := GetInstance3()
fmt.Println(e1.name)
e2 := GetInstance3()
fmt.Println(e2.name)
}
Паттерн синглтон — это шаблон проектирования, который часто используется в разработке Я делаю свой собственный веб-фреймворк.silsuer/bingoкогда Этот режим используется для управления переменными среды, управления элементами конфигурации и т. д.
Я хочу реализовать все шаблоны проектирования с помощью golang и открыть новую ямуsilsuer/golang-design-patterns, Это первый, и он будет обновляться в будущем. Пожалуйста, заберите его, если он вам нужен~
Исходный код этой статьи находится в этом репозитории:шаблон дизайна голанг
Рекламируйте и рекомендуйте фреймворк go web, написанный вамиbingo, просить звезду, просить пиар ~