Skip to content

Commit

Permalink
add singleton
Browse files Browse the repository at this point in the history
  • Loading branch information
sioncojp committed Apr 23, 2018
1 parent ab4c367 commit 699bf7c
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 0 deletions.
23 changes: 23 additions & 0 deletions singleton/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Singleton
あるクラスに対してインスタンスが1つだけ生成されるよう制限する

### メリット
* クラスのインスタンスが1つしか生成されない

### デメリット
* 本当に1つでいいのか?要件の変化を織り込んでない
* ユニットテストの妨げになりがち
* mockに差しかえれない
* どのような順序でもテストが可能でないといけない
* singletonを明示的に殺す方法はない
* 複数のsingletonがある場合、どの順序でクリーンアップされるかは決まってない
* 依存関係上にあると...

### ポイント
* 必要なインスタンスが絶対に1つだけと確信したら使う
* あとDIコンテナに実装してあげると依存関係気にしなくていいよね

### 例題
* 本の貸出しリスト
* Ruby, Perlの本は貸出し中かどうか、貸出しリストが複数あったらわからないから
* singletonパターンを使って、貸出しリストはこの1冊のみ と保証する
34 changes: 34 additions & 0 deletions singleton/singleton.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package singleton

import (
"fmt"
"sync"
)

type lendingList struct {
Books []Book
}

var lendingListInstance *lendingList
var once sync.Once

func GetLendingList() *lendingList {
once.Do(func() {
// 初期化
lendingListInstance = &lendingList{}
})
return lendingListInstance
}

type Book string

func (l *lendingList) Lending(b Book) {
for _, v := range l.Books {
if v == b {
fmt.Printf("%v貸りられてるよ\n", b)
return
}
}
l.Books = append(l.Books, b)
fmt.Printf("%vを借りるね\n", b)
}
24 changes: 24 additions & 0 deletions singleton/singleton_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package singleton

import "testing"

func TestSingleton(t *testing.T) {
ch := make(chan interface{})
defer close(ch)

books := []Book{"ruby", "perl", "ruby"}

for _, b := range books {
go run(ch, b)
}

for i := 1; i <= len(books); i++ {
<-ch
}
}

func run(ch chan interface{}, b Book) {
s := GetLendingList()
ch <- s
s.Lending(b)
}

0 comments on commit 699bf7c

Please sign in to comment.