web-dev-qa-db-ja.com

移動中のシングルトン

Goプログラミング言語でシングルトンデザインパターンをどのように実装しますか?

38
Ben Noland

シングルトンパターンを実装するかどうかの引数を別にしておくのは良い考えです。可能な実装は次のとおりです。

_package singleton

type single struct {
        O interface{};
}

var instantiated *single = nil

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

singleinstantiatedはプライベートですが、New()はパブリックです。したがって、New()を経由せずにsingleを直接インスタンス化することはできず、プライベートブール値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
}
_

また、パッケージをasシングルトンと考えるだけのhasan jの提案も参照してください。そして最後に、他の人が示唆していることを考慮してください。シングルトンはしばしば問題のある実装の指標です。

42
esm

曲がる方法を見つける前に、思い通りに、いくつかの記事を見てみましょう。

要約すると、時間が経つにつれて人々はシングルトンが最適ではないことを発見し、テスト駆動型の開発を試みようとしている場合は、imho特に:多くのレベルはグローバル変数と同じくらい悪いです。

[免責事項:私はあなたの質問に対する厳密な回答ではないことを知っていますが、それは本当に関連しています]

11
jkp

変数と関数をパッケージレベルで配置するだけです。

同様の質問も参照してください: Pythonでシングルトンを作成する方法

9
hasen

最善のアプローチは次のとおりです。

 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

7
sadlil

once package を使用して初期化を行うことができます:

これにより、initメソッドが1回だけ呼び出されることが保証されます。

3
marketer

次のコードでわかるように、簡単な方法です。

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

1
omotto

必要なオブジェクトの単一の静的な最終的な定数のグローバルなアプリケーション全体のインスタンスがあるだけです。

ただし、これはOOパラダイムとは矛盾します。その使用は、可変オブジェクトではなく、プリミティブおよび不変オブジェクトに限定する必要があります。

1
BalusC

Once.Doは、コードを1回だけ実行することを真剣に考えています。つまり、パニックが発生したとしても、コードはalwaysが1回だけ実行されます。

から https://golang.org/pkg/sync/#Once.Do

F(注:かつてのロジック)でパニックが発生した場合、Doはそれが戻ったと見なします。 Doの今後の呼び出しは、fを呼び出さずに戻ります。

代わりにmutexを使用して、グローバル構成変数の一意の初期化を確実にし、この制限を克服しました。

1