Singleton in go

可紊 提交于 2019-12-20 08:28:00

问题


How does one implement the Singleton design pattern in the go programming language?


回答1:


Setting aside the argument of whether or not implementing the singleton pattern is a good idea, here's a possible implementation:

package singleton

type single struct {
        O interface{};
}

var instantiated *single = nil

func New() *single {
        if instantiated == nil {
                instantiated = new(single);
        }
        return instantiated;
}

single and instantiated are private, but New() is public. Thus, you can't directly instantiate single without going through New(), and it tracks the number of instantiations with the private boolean instantiated. Adjust the definition of single to taste.

However, as several others have noted, this is not thread-safe, unless you're only initializing your singleton in init(). A better approach would be to leverage sync.Once to do the hard work for you:

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
}

See also, hasan j's suggestion of just thinking of a package as a singleton. And finally, do consider what others are suggesting: that singletons are often an indicator of a problematic implementation.




回答2:


Before trying to find a way to bend Go to your will, you might want to take a look at some articles:

  • SINGLETON - the anti-pattern!

  • Singletons are Pathological Liars

  • Root Cause of Singletons.

In summary, over time people have found singletons to be less than optimal, and imho especially if you are trying to do any test-driven development: on many levels they are pretty much as bad as global variables.

[disclaimer: I know its not a strict answer to your question but it really is relevant]




回答3:


Just put your variables and functions at the package level.

Also see similar question: How to make a singleton in Python




回答4:


I think that in a concurrent world we need to be a bit more aware that these lines are not executed atomically:

if instantiated == nil {
    instantiated = new(single);
}

I would follow the suggestion of @marketer and use the package "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 
}



回答5:


The best approach will be:

 package singleton

 import "sync"

 type singleton struct {
 }

 var instance *singleton
 var once sync.Once

 func GetInstance() *singleton {
     once.Do(func() {
         instance = &singleton{}
     })
     return instance
 }

You should read this Link




回答6:


You can do initialization using the once package:

This will ensure that your init methods only get called once.




回答7:


Just have a single static, final, constant, global, application-wide instance of the Object you want.

This however contradicts the OO paradigm. Its use should be limited to primitives and immutable objects, not to mutable objects.




回答8:


You should be aware that Once.Do is serious about executing the code only once. That means, the code is always executed only once, even though it might have panicked:

from https://golang.org/pkg/sync/#Once.Do

If f (note: the once logic) panics, Do considers it to have returned; future calls of Do return without calling f.

I used mutexes instead to ensure unique initialisation of a global configuration variable to overcome this restriction:

  • https://golang.org/pkg/sync/#Mutex
  • https://gobyexample.com/mutexes



回答9:


Easy peasy as you can see in the following code:

package main

import (
    "fmt"
    "sync"
)

type singleton struct {
    count int
    sync.RWMutex
}

var instance singleton 

func GetInstance() *singleton {
    return &instance 
}

func (s *singleton) AddOne() {
    s.Lock()
    defer s.Unlock()
    s.count++
}

func (s *singleton) GetCount() int {
    s.RLock()
    defer s.RUnlock()
    return s.count
}

func main() {
    obj1 := GetInstance()
    obj1.AddOne()
    fmt.Println(obj1.GetCount())
    obj2 := GetInstance()
    obj2.AddOne()
    fmt.Println(obj2.GetCount())    
    obj3 := GetInstance()
    obj3.AddOne()
    fmt.Println(obj3.GetCount())
}

Expected result would be:

1 2 3

Because you're accessing to the same resource. That's the reason I've added mutex in order to be concurrent proven accessing count attribute from multiple processes. :-)

Source:

https://play.golang.org/p/2XnLztX8Gs5



来源:https://stackoverflow.com/questions/1823286/singleton-in-go

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!