こんにちは、KOUKIです。
この記事では、デザインパターンの一つであるBuilderパターンについて、紹介しています。
前回は、BuilderパターンのParameterを実装することで、インスタンス生成なしで機能を利用できる方法を紹介しましたが、今回は、それの関数バージョンを紹介したいと思います。
Functional Builderの実装
早速、実装していきましょう。
Email構造体
最初に、Build(構築)対象の構造体を定義します。
1 2 3 |
type email struct { from, to, subject, body string } |
利用者側では、この構造体をインスタンス化をせず、関数の呼び出しのみで利用できるようにします。
Builder構造体と関数
次に、Builder構造体と関数 Typeを定義します。
1 2 3 4 |
type emailSet func(*email) type EmailBuilder struct { actions []emailSet } |
ここが、今回の肝です。emailSet Typeは、emailを引数にした関数をTypeで持ち、EmailBuilderのパラメータとして宣言します。
プロパティ設定メソッドの実装
次は、プロパティ設定用のメソッドを定義します。
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 |
func (b *EmailBuilder) From(from string) *EmailBuilder { b.actions = append(b.actions, func(e *email) { e.from = from }) return b } func (b *EmailBuilder) To(to string) *EmailBuilder { b.actions = append(b.actions, func(e *email) { e.to = to }) return b } func (b *EmailBuilder) Subject(subject string) *EmailBuilder { b.actions = append(b.actions, func(e *email) { e.subject = subject }) return b } func (b *EmailBuilder) Body(body string) *EmailBuilder { b.actions = append(b.actions, func(e *email) { e.body = body }) return b } |
actionsには、emailSet Typeのスライスが必要なので、それぞれのメソッド内で無名関数を定義し、appendで追加しています。
また、戻り値をEmailBuilderのレシーバーにすることで、メソッドを数珠繋ぎで呼び出すことができます。※詳細は、「使ってみる」項目を参照してください
Buildメソッドの定義
最後に、Buildメソッドを定義します。
1 2 3 4 5 6 7 8 9 10 |
func (b *EmailBuilder) Build() *email { e := email{} for _, a := range b.actions { // プロパティセット a(&e) } return &e } |
b.actionsには、メソッドを呼び出した結果(無名関数)が格納されているので、それをループで回し、プロパティを設定する流れです。
使ってみる
実際に使ってみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
func SendMail(email *email) { fmt.Println(email) } func main() { b := EmailBuilder{} SendMail(b.From("selfnote@com.co.jp"). To("selfnote2@com.co.jp"). Subject("Builder Pattern"). Body("Would you like to learn builder pattern?"). Build()) } |
各メソッドの戻り値は、EmailBuilderのレシーバーにしてあるので、上記のように数珠繋ぎで呼び出すことができます。そして、最後の仕上げとしてBuildメソッドを呼び出すことで、Build(構築)するという流れです。
1 2 |
$ go run main.go &{selfnote@com.co.jp selfnote2@com.co.jp Builder Pattern Would you like to learn builder pattern?} |
まとめ
本記事で、Builderパターンは完了です。ガンガン使っていきましょう^^
2: レシーバーを返すことで、数珠繋ぎにメソッドを呼び出せる
3: 共通の構造体を定義することで、別々のBuilderで得た結果を統合できる
4: インスタンス化がシンプルになる
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 54 55 56 57 58 59 60 61 62 63 64 |
package main import "fmt" type email struct { from, to, subject, body string } type emailSet func(*email) type EmailBuilder struct { actions []emailSet } func (b *EmailBuilder) From(from string) *EmailBuilder { b.actions = append(b.actions, func(e *email) { e.from = from }) return b } func (b *EmailBuilder) To(to string) *EmailBuilder { b.actions = append(b.actions, func(e *email) { e.to = to }) return b } func (b *EmailBuilder) Subject(subject string) *EmailBuilder { b.actions = append(b.actions, func(e *email) { e.subject = subject }) return b } func (b *EmailBuilder) Body(body string) *EmailBuilder { b.actions = append(b.actions, func(e *email) { e.body = body }) return b } func (b *EmailBuilder) Build() *email { e := email{} for _, a := range b.actions { // プロパティセット a(&e) } return &e } func SendMail(email *email) { fmt.Println(email) } func main() { b := EmailBuilder{} SendMail(b.From("selfnote@com.co.jp"). To("selfnote2@com.co.jp"). Subject("Builder Pattern"). Body("Would you like to learn builder pattern?"). Build()) } |
コメントを残す
コメントを投稿するにはログインしてください。