こんにちは、KOUKIです。
この記事では、デザインパターンの一つであるMementoパターンについて紹介します。
<目次>
デザインパターンまとめ
シチュエーション
Memento は、「記念品」や「形見」を意味する英単語です。
Memento パターンは、 インスタンスのあるときの状態をスナップショットとして保存しておくことで、 その時のインスタンスの状態を復元することを可能にするものです。
例えば、DB更新を例に考えてみましょう。
特定の商品を購入して行って、商品購入後にキャンセルしたいとします。つまり、買わなかった状態にDBの状態を戻したいわけですね。
これをMementoパターンを使って実装してみましょう。
Mementoパターンの適用
Memento構造体
最初に、Memento構造体を実装します。
1 2 3 |
type Memento struct { buyNum int } |
この構造体が、スナップショット(更新前のDBの状態)になります。
DB構造体
次に、DB構造体を実装します。
1 2 3 |
type DB struct { buyNum int } |
DBコンストラクタ
DBのコンストラクタを実装しましょう。
1 2 3 |
func NewDB(num int) (*DB, *Memento) { return &DB{buyNum: num}, &Memento{buyNum: num} } |
戻り値として、Mementoインスタンスを返しています。これで、初期化時のDBのスナップショットが取得できます。
DBのメソッド
DBのメソッドを実装しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
func (d *DB) Buy(num int) *Memento { fmt.Println(fmt.Sprintf("商品を%d個購入しました", num)) d.buyNum += num // スナップショットを残す return &Memento{num} } // 商品の購入を元に戻す func (d *DB) Restore(m *Memento) { fmt.Println(fmt.Sprintf("商品を%d個キャンセルしました", m.buyNum)) d.buyNum -= m.buyNum } func (d *DB) String() { fmt.Println(fmt.Sprintf("トータルの購入数は%dです", d.buyNum)) } |
Buy/Restoreメソッドのパラメータには、Mementoを指定しています。これにより、商品のスナップショットを残せますし、リストアも可能になりました。
使ってみよう
ここまで実装したプログラムを使ってみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
func main() { myDB, snapshot0 := NewDB(0) snapshot1 := myDB.Buy(50) snapshot2 := myDB.Buy(25) myDB.String() // リストア1 myDB.Restore(snapshot1) myDB.String() // リストア2 myDB.Restore(snapshot2) myDB.String() // リストア0(一気に初期の状態に戻せる) myDB.Restore(snapshot0) myDB.String() } |
1 2 3 4 5 6 7 8 9 10 |
$ go run main.go 商品を50個購入しました 商品を25個購入しました トータルの購入数は75です 商品を50個キャンセルしました トータルの購入数は25です 商品を25個キャンセルしました トータルの購入数は0です 商品を0個キャンセルしました トータルの購入数は0です |
こんな感じですね。
まとめ
Mementoパターンは、結構使えそうな気がしますね。
インスタンスの状態をローカルに保存しておいて、もし何か重大な失敗があれば元に戻す仕組みを作っておく、みたいな感じなので。
デザインパターンを学ぶと、インターフェースや構造体の新しい使い方に気づくことができるので、結構おすすめです^^
それでは、また!
次回
面白そうなので、次回に続きます。
Go言語まとめ
ソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
package main import "fmt" type DB struct { buyNum int } type Memento struct { buyNum int } func NewDB(num int) (*DB, *Memento) { return &DB{buyNum: num}, &Memento{buyNum: num} } func (d *DB) Buy(num int) *Memento { fmt.Println(fmt.Sprintf("商品を%d個購入しました", num)) d.buyNum += num // スナップショットを残す return &Memento{num} } // 商品の購入を元に戻す func (d *DB) Restore(m *Memento) { fmt.Println(fmt.Sprintf("商品を%d個キャンセルしました", m.buyNum)) d.buyNum -= m.buyNum } func (d *DB) String() { fmt.Println(fmt.Sprintf("トータルの購入数は%dです", d.buyNum)) } func main() { myDB, snapshot0 := NewDB(0) snapshot1 := myDB.Buy(50) snapshot2 := myDB.Buy(25) myDB.String() // リストア1 myDB.Restore(snapshot1) myDB.String() // リストア2 myDB.Restore(snapshot2) myDB.String() // リストア0 myDB.Restore(snapshot0) myDB.String() } |
コメントを残す
コメントを投稿するにはログインしてください。