1. Что такое паттерн Одиночка
Паттерн Одиночка - это порождающий паттерн проектирования, который обеспечивает наличие только одного экземпляра класса и предоставляет глобальную точку доступа к этому экземпляру для извлечения. Паттерн Одиночка широко используется в ситуациях, где необходимо совместное использование ресурсов или управление доступом к конкретному экземпляру.
2. Характеристики и преимущества паттерна Одиночка
Паттерн Одиночка обладает следующими характеристиками и преимуществами:
- Гарантирует наличие только одного экземпляра объекта класса
- Предоставляет глобальную точку доступа для внешнего кода для получения экземпляра
- Избегает повторного создания экземпляров, экономя ресурсы системы
3. Сценарии применения паттерна Одиночка
Паттерн Одиночка подходит для следующих сценариев применения:
- Логгеры: Обеспечение наличия только одного логгера для всей системы для предотвращения дублирования журналирования.
- Пул подключений к базе данных: В условиях высокой конкурентной нагрузки использование паттерна Одиночка позволяет избежать частого создания и уничтожения подключений к базе данных.
4. Реализация паттерна Одиночка в Golang
В Golang существуют различные способы реализации паттерна Одиночка. Ниже представлены два распространенных способа реализации.
4.1. Реализация с отложенной и жадной инициализацией
Отложенная инициализация создает экземпляр объекта при первом использовании, в то время как жадная инициализация создает экземпляр объекта при запуске программы.
// Реализация паттерна Одиночка с отложенной инициализацией
package singleton
type Singleton struct {
}
var instance *Singleton
func GetInstance() *Singleton {
if instance == nil {
instance = &Singleton{}
}
return instance
}
// Реализация паттерна Одиночка с жадной инициализацией
package singleton
type Singleton struct {
}
var instance *Singleton = &Singleton{}
func GetInstance() *Singleton {
return instance
}
4.2. Проблемы безопасности потоков в паттерне Одиночка
Указанный метод реализации отложенной инициализации может иметь проблемы в многопоточной среде, поскольку несколько потоков могут одновременно войти в условие if instance == nil
, что может привести к созданию нескольких экземпляров.
4.3. Реализация потокобезопасного паттерна Одиночка с использованием sync.Once
Использование sync.Once
обеспечивает выполнение кода инициализации только одним горутином, тем самым решая проблему безопасности потоков.
// Реализация потокобезопасного паттерна Одиночка с использованием sync.Once
package singleton
import (
"sync"
)
type Singleton struct {
}
var instance *Singleton
var once sync.Once
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{}
})
return instance
}
4.4. Реализация потокобезопасной отложенной инициализации паттерна Одиночка с использованием sync.Mutex
Другой способ реализации потокобезопасной отложенной инициализации паттерна Одиночка - использовать sync.Mutex
для блокировки и обеспечения выполнения операции инициализации только одной горутиной.
// Реализация потокобезопасной отложенной инициализации паттерна Одиночка с использованием sync.Mutex
package singleton
import (
"sync"
)
type Singleton struct {
}
var instance *Singleton
var mu sync.Mutex
func GetInstance() *Singleton {
if instance == nil {
mu.Lock()
defer mu.Unlock()
if instance == nil {
instance = &Singleton{}
}
}
return instance
}