单身人士去吧

时间:2009-12-01 00:12:58

标签: design-patterns go singleton anti-patterns

如何在go编程语言中实现Singleton设计模式?

10 个答案:

答案 0 :(得分:37)

抛开关于是否实现单例模式的论点是一个好主意,这是一个可能的实现:

package singleton

type single struct {
        O interface{};
}

var instantiated *single = nil

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

singleinstantiated是私有的,但New()是公开的。因此,您无法在不经过single的情况下直接实例化New(),并且它会使用私有布尔值instantiated跟踪实例化的数量。调整single的定义以品尝。

但是,正如其他几个人noted一样,这不是线程安全的,除非你只是在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
}

另请参阅,hasan j建议将包视为单身。最后,请考虑其他人的建议:单身人士往往是有问题的实施的指标。

答案 1 :(得分:11)

在尝试找到弯曲的方法之前,你可能想看看一些文章:

总而言之,随着时间的推移,人们发现单身人士不是最优的,如果你想尝试任何以测试为导向的开发,那么他们就会非常:在许多层面上他们都差不多全局变量。

[免责声明:我知道这不是你问题的严格答案,但它确实是相关的]

答案 2 :(得分:9)

只需将变量和函数放在包级别。

另见类似问题:How to make a singleton in Python

答案 3 :(得分:8)

我认为在并发的世界中,我们需要更多地意识到这些行不是以原子方式执行的:

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 
}

答案 4 :(得分:5)

最好的方法是:

 package singleton

 import "sync"

 type singleton struct {
 }

 var instance *singleton
 var once sync.Once

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

您应该阅读此Link

答案 5 :(得分:3)

您可以使用once package

进行初始化

这将确保只调用一次init方法。

答案 6 :(得分:1)

只需要一个所需对象的静态,最终,常量,全局,应用程序范围的实例。

然而,这与OO范式相矛盾。它的使用应限于基元和不可变对象,而不是可变对象。

答案 7 :(得分:1)

您应该知道Once.Do对于仅执行一次代码非常认真。这意味着代码总是只执行一次,即使它可能有恐慌:

来自https://golang.org/pkg/sync/#Once.Do

  

如果f(注意:曾经的逻辑)恐慌,请考虑它已经返回;将来调用Do而不调用f。

我使用互斥锁来确保全局配置变量的唯一初始化以克服此限制:

答案 8 :(得分:1)

在下面的代码中可以轻松看到

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())
}

预期结果将是:

  

1 2 3

因为您正在访问相同的资源。这就是我添加互斥锁以便同时验证从多个进程访问 count 属性的原因。 :-)

来源:

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

答案 9 :(得分:0)

我认为,如果您想要在 Go 中实现类似单例的功能,您应该尝试考虑您想要实现的目标。与 Java 或 C# 不同,Go 没有“静态”类的概念,因此传统区分不太清楚。在我看来,您希望从单例中获得的关键点是不允许其他人构建它。为此,我认为它可以更简单地实现:导出一个接口,实现一个实现该接口的未导出的类,然后导出它的单个实例。例如:

var DefaultTransformer Transformer = &transformer{}

type Transformer interface {
    Transform(s string) string
}

type transformer struct {
    
}

func (t *transformer) Transform(s string) string {
    return s + "1"
}

var _ Transformer = (*transformer)(nil)

正如其他答案所示,您可以在 Go 中实现单例模式的字面意思有很多,但它们给我的印象是从必须完全复制模式的前提开始的答案,而不是从解决真正的问题开始您在 Go 中遇到的问题。