Singletonパターン

最終更新:2020/05/18


この記事の内容は

java言語で学ぶデザインパターン

を参考にしてGo言語に置き換えた内容になってます。

わかりにくい箇所は私の責任であり、java言語で学ぶデザインパターンのせいではありません。

目次

  1. Singletonパターンとは
  2. Singletonパターンの構成
  3. サンプルコード
  4. サンプルコードの説明
  5. サンプルコードの実行
  6. 設計のヒント
  7. 関連しているパターン

1. Singletonパターンとは

Singletonパターンは、指定したインスタンスが絶対に1個しかないことを保障します。

2. Singletonパターンの構成

Singleton

Singletonは唯一のインスタンスを得るための関数をもちます。

このメソッドはいつも同じインスタンスを返します。

3. サンプルコード

package singleton import ( "fmt" "reflect" "sync" ) type Singleton struct { // Some fields } var singleton *Singleton var once sync.Once func GetInstance() *Singleton { once.Do(func() { // 初期化 singleton = &Singleton{} fmt.Println("インスタンスを生成しました。") }) return singleton } // Client func Client() { obj1 := GetInstance() obj2 := GetInstance() if reflect.DeepEqual(obj1, obj2) { fmt.Println("obj1とobj2は同じインスタンスです。") } else { fmt.Println("obj1とobj2は同じインスタンスではありません。") } }

4. サンプルコードの説明

上記のサンプルコードの構成は以下の通りです。

Singleton

Singletonの役割は、いつも同じインスタンスを返すことです。

メソッドでいつも同じインスタンスを返すようにします。

サンプルコードだとGetInstance関数が担います。

func GetInstance() *Single { once.Do(func() { // 初期化 singleton = &Single{} fmt.Println("インスタンスを生成しました。") }) return sharedInstance }

once.Do

once.Doは、Onceのインスタンスに対して初めてDoが呼び出される場合にのみ、関数fを呼び出します。

なので上記のコードでは、最初のDoで

// 初期化 singleton = &Single{} fmt.Println("インスタンスを生成しました。")

が実行されます。

reflect.DeepEqual

reflect.DeepEqualは、structの比較に使います。

アドレスは別で良くて、単純に指しているものが同じ内容か確認します。

5. サンプルコードの実行

サンプルコードをmain関数で呼び出します。

package main import ( "github.com/java-lang-programming/marsa/singleton" ) func main() { singleton.Client() }

実行すると以下が出力されます。

# go run main.go インスタンスを生成しました。 obj1とobj2は同じインスタンスです。

6. 設計のヒント

なぜ制限を設ける必要があるのか

インスタンスが一つしかないという保証があれば、その前提条件の下でプログラミングができる

7. 関連しているパターン

以下のパターンでよく使います。

  • Abstract Factoryパターン
  • Builderパターン
  • Facadeパターン
  • Prototpeパターン