Синглтон в пути
-
22-07-2019 - |
Вопрос
Как реализовать шаблон проектирования Singleton на языке программирования go?
Решение
Если оставить в стороне аргумент того, является ли реализация шаблона синглтона хорошей идеей, вот возможная реализация:
package singleton
type single struct {
O interface{};
}
var instantiated *single = nil
func New() *single {
if instantiated == nil {
instantiated = new(single);
}
return instantiated;
}
single
и экземпляр
являются частными, но New ()
является общедоступным. Таким образом, вы не можете напрямую создать экземпляр single
, не пройдя через New ()
, и он отслеживает количество экземпляров с помощью закрытого логического instantiated
. Настройте определение single
по вкусу.
Однако, поскольку некоторые другие отметили , это не так. поточно-ориентированный, если только вы не инициализируете свой синглтон в init ()
. Лучшим подходом было бы использовать sync.Once
для выполнения тяжелой работы за вас:
package singleton
import "sync"
type single struct {
O interface{};
}
var instantiated *single
var once sync.Once
func New() *single {
once.Do(func() {
instantiated = &single{}
})
return instantiated
}
Смотрите также предложение Хасана j просто думать о пакете как как об одиночке. И, наконец, подумайте над тем, что предлагают другие: синглтоны часто являются индикатором проблемной реализации.
Другие советы
Прежде чем пытаться найти способ подчинить Go своей воле, возможно, вам стоит взглянуть на несколько статей:
Подводя итог, можно сказать, что со временем люди пришли к выводу, что синглтоны не оптимальны, и, по моему мнению, особенно если вы пытаетесь выполнить какую-либо разработку через тестирование:на многих уровнях они так же плохи, как и глобальные переменные.
[отказ от ответственности:Я знаю, что это не строгий ответ на ваш вопрос, но это действительно важно]
Просто поместите свои переменные и функции на уровне пакета.
Также см. аналогичный вопрос: Как создать синглтон в Python
Я думаю, что в параллельном мире нам нужно немного больше понимать, что эти строки не выполняются атомарно:
if instantiated == nil {
instantiated = new(single);
}
Я бы последовал предложению @marketer и использовал бы пакет " sync "
import "sync"
type MySingleton struct {
}
var _init_ctx sync.Once
var _instance *MySingleton
func New() * MySingleton {
_init_ctx.Do( func () { _instance = new(MySingleton) } )
return _instance
}
Наилучшим подходом будет:
package singleton
import "sync"
type singleton struct {
}
var instance *singleton
var once sync.Once
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
Вам следует прочитать эту ссылку
Вы можете выполнить инициализацию, используя один раз пакет :
Это гарантирует, что ваши методы init будут вызываться только один раз. Р>
Просто имейте один статический, конечный, постоянный, глобальный, экземпляр приложения для всего объекта.
Это, однако, противоречит парадигме ОО. Его использование должно быть ограничено примитивами и неизменяемыми объектами, а не изменяемыми объектами.
Вы должны знать, что Once.Do
серьезно относится к выполнению кода только один раз.Это означает, что код всегда выполнен только один раз, даже если он запаниковал:
от https://golang.org/pkg/sync/#Once.Do
Если f (примечание:некогда логика) паникует, До считает, что он вернулся;будущие вызовы Do возвращаются без вызова f.
Вместо этого я использовал мьютексы, чтобы обеспечить уникальную инициализацию глобальной переменной конфигурации и преодолеть это ограничение: