【Go言語】個人的に1番良さげなDecoratorパターンの実装
はじめに
Golangで実装するDecoratorパターンについて勉強した際、参考資料に載せてあるように多くの方法がありました。
どんな実装が1番良いか模索した結果、個人的に↓で書いたコードが一番読みやすくて良いかなと思いました。
コード
今回実装したコードについて説明します。
Decoratorパターンを使ってデフォルトのアバターをカスタマイズし、装備を着けて強化していくプログラムになっています。
仮にDecoratorパターンを使わない場合、最初から装飾されたオブジェクトを用意しておいて生成する方法になると思いますが、
装備が増えた時に全パターン分用意することになるので、コード数がかなり多くなってしまいます。
なら装備を部品として用意してアバターに柔軟に着けていくのが一番良さそうです。
type Avatar struct {
Name string
HP int
WeaponList []string
}
type CustomizerFunc func(*Avatar) *Avatar
func Custom(i *Avatar, customizerFuncs ...CustomizerFunc) {
for _, customizerFunc := range customizerFuncs {
i = customizerFunc(i)
}
}
func Attach(weapon string, hp int) CustomizerFunc {
return CustomizerFunc(func(i *Avatar) *Avatar {
i.WeaponList = append(i.WeaponList, weapon)
i.HP += hp
return i
})
}
func main() {
// default Avatar
avatar := &Avatar{Name: "久川善法", HP: 100}
fmt.Printf("カスタマイズ前:%+v\n", avatar)
// custom Avatar
Custom(avatar, Attach("gun", 1), Attach("helmet", 10))
fmt.Printf("カスタマイズ後:%+v", avatar)
}
// カスタマイズ前:&{Name:久川善法 HP:100 WeaponList:[]}
// カスタマイズ後:&{Name:久川善法 HP:111 WeaponList:[gun helmet]}
コードの解説
・型定義
予約語であるtype
を使って、既存の型や型リテラルに別名をつけることができます。
関数型のCustomizerFunc型
を定義しました。
引数でAvatar
を受け取りAvatar
を返す関数です。
type CustomizerFunc func(*Avatar) *Avatar
・デコレータパターンの実装
上記で定義したCustomizerFunc型
を複数受け取り、順番にその関数を実行しています。
i = customizerFunc(i)
とあるので、Avatar
を受け取ってAvatar
を返しています。
func Custom(i *Avatar, customizerFuncs ...CustomizerFunc) {
for _, customizerFunc := range customizerFuncs {
i = customizerFunc(i)
}
}
※余談
i = customizerFunc(i)
この実装がわかりにくいかもしれないので、他の視点からも。
func main() {
// 無名関数を定義しています。
function := func(str string) string {
return "*" + str + "*"
}
// 引数を渡して無名関数を実行しています。
f := function("golang")
fmt.Println(f)
}
// *golang*
・部品の用意
返り値はCustomizerFunc
なので、return CustomizerFunc()
を返しています。
CustomizerFunc型
はfunc(*Avatar) *Avatar
のエイリアスなので、functionを書きます。
そして引数で受け取ったAvatar
のHPやWeaponListに値を追加して返却しています。
func Attach(weapon string, hp int) CustomizerFunc {
return CustomizerFunc(func(i *Avatar) *Avatar {
i.WeaponList = append(i.WeaponList, weapon)
i.HP += hp
return i
})
}
・余談
個人的にreturn CustomizerFunc()
がわかりにくかったです。
簡単な例で同じ実装をすると以下のようになります。
type Number uint
func main() {
num := Number(11)
fmt.Println(num)
}
・最後にDecoratorを呼び出す
最後にavatar
を第一引数に渡し、第二引数以降のAttach
で装飾しています。
Custom(avatar, Attach("gun", 1), Attach("helmet", 10))
最後に
Function型のエイリアスを定義することがあまりないので、最初はコードを読むのに苦労しました。
簡単な例に置き換えてみるととてもわかりやすかったです。
個人的に実装してきたデザインパターンの中では一番好きなコードです。
参考資料
-
https://gist.github.com/alehano/8785933
- Golangっぽいです。
-
https://github.com/monochromegane/go_design_pattern/blob/master/decorator/decorator.go
- 書籍に書いてあるような書き方の印象
-
https://github.com/alex-leonhardt/go-decorator-pattern
- 9つのDecoratorパターンを紹介しています。すごい色々ある。
-
https://gist.github.com/nightmouse/65cb8a01d274c4a6a53e
- 個人的に一番参考にした記事です。
- Golangっぽいです。
- 書籍に書いてあるような書き方の印象
- 9つのDecoratorパターンを紹介しています。すごい色々ある。
- 個人的に一番参考にした記事です。
Author And Source
この問題について(【Go言語】個人的に1番良さげなDecoratorパターンの実装), 我々は、より多くの情報をここで見つけました https://qiita.com/yoshinori_hisakawa/items/d265c01ffa8a90b9b43f著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .