Singleton em go
-
22-07-2019 - |
Pergunta
Como implementar um Singleton design pattern) na linguagem de programação go?
Solução
Deixando de lado o argumento de se implementar ou não o padrão de singleton é uma boa idéia, aqui está uma possível implementação:
package singleton
type single struct {
O interface{};
}
var instantiated *single = nil
func New() *single {
if instantiated == nil {
instantiated = new(single);
}
return instantiated;
}
single
e instantiated
são privados, mas New()
é público. Assim, você não pode instanciar diretamente single
sem passar New()
, e rastreia o número de instanciações com o booleano privado instantiated
. Ajustar a definição de single
provar.
No entanto, como vários outros têm notado, isso não é seguro para fios, a menos que você esteja apenas inicializando seu singleton em init()
. Uma abordagem melhor seria alavancar sync.Once
Para fazer o trabalho duro para você:
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
}
Veja também, a sugestão de Hasan J de apenas pensar em um pacote Como um singleton. E, finalmente, considere o que os outros estão sugerindo: que os singletons geralmente são um indicador de uma implementação problemática.
Outras dicas
Antes de tentar encontrar uma maneira de dobrar o Ir à sua vontade, você pode querer dar uma olhada em alguns artigos:
Em resumo, ao longo do tempo as pessoas têm encontrado gestações únicas para ser menos do que o ideal e, imho especialmente se você está tentando fazer qualquer desenvolvimento orientado a testes:em muitos níveis, e eles são praticamente tão ruim como variáveis globais.
[termo de responsabilidade:Eu sei que não é um rigoroso resposta para a sua pergunta, mas ele realmente é relevante]
Basta colocar as variáveis e funções em nível de pacote.
Veja também a pergunta semelhante: Como fazer um singleton em Python
Eu acho que em um mundo simultâneo precisamos estar um pouco mais conscientes de que essas linhas não são executadas atomicamente:
if instantiated == nil {
instantiated = new(single);
}
Eu seguiria a sugestão de @marketer e usaria o pacote "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
}
A melhor abordagem será:
package singleton
import "sync"
type singleton struct {
}
var instance *singleton
var once sync.Once
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
Você deveria ler isso Link
Você pode fazer a inicialização usando o Uma vez pacote:
Isso garantirá que seus métodos inits sejam chamados apenas uma vez.
Basta ter uma única instância estática, final, constante, global e em toda a aplicação do objeto que você deseja.
No entanto, isso contradiz o paradigma OO. Seu uso deve ser limitado a primitivos e objetos imutáveis, não a objetos mutáveis.
Você deve estar ciente de que Once.Do
é sério sobre a execução do código apenas uma vez. Isso significa que o código é sempre executado apenas uma vez, mesmo que possa ter entrado em pânico:
a partir de https://golang.org/pkg/sync/#once.do
Se f (nota: a lógica única) entrar em pânico, considere retornar; Chamadas futuras do retorno sem ligar f.
Em vez disso, usei mutexes para garantir a inicialização exclusiva de uma variável de configuração global para superar essa restrição: