こんにちは、KOUKIです。
この記事では、前回に引き続き、デザインパターンの一つであるVisitorパターンについて紹介します。
デザインパターンまとめ
シチュエーション
前回の復習ですが、Visitor は、「訪問者」を意味する英単語で、Visitor パターンは、既存のコードを変更せずに既存のクラス階層に新しい処理を追加できるパターンです。
Classic Visitorパターンの適用
Go言語にはClassの概念はないですが、インターフェースを使ってClassを実装するみたいな書き方もできます。
前回作成したソースコードを、Classic Visitorパターンで書き換えてみましょう。
クラスの代わりにインターフェース
まず、クラスの代わりとなるインターフェースを実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package main import ( "fmt" "strings" ) type ExpressionVisitor interface { VisitEyeExpression(ee *EyeExpression) VisitMouthExpression(me *MouthExpression) VisitOtherExpression(oe *OtherExpression) VisitCombineExpression(ce *CombineExpression) } |
このExpressionVisitorインターフェースは、Visitor(Expression)を受け入れるメソッドを持ちます。
Visitorの共通インターフェース
次はVisitorが持つ共通のインターフェースを実装します。
1 2 3 4 |
// 共通のインターフェース type Expression interface { Accept(ev ExpressionVisitor) } |
Acceptの引数にExpressionVisitor(クラスのようなもの)を渡しているので、このインスタンスは、ExpressionVisitorに設定した4つのメソッドを持ちます。
Visitor
次に、Visitorを実装しましょう。
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 |
// Visitor -「目」 type EyeExpression struct { eye string } func (e *EyeExpression) Accept(ev ExpressionVisitor) { ev.VisitEyeExpression(e) } // Visitor -「口」 type MouthExpression struct { mouth string } func (e *MouthExpression) Accept(ev ExpressionVisitor) { ev.VisitMouthExpression(e) } // Visitor -「その他」 type OtherExpression struct { other string } func (e *OtherExpression) Accept(ev ExpressionVisitor) { ev.VisitOtherExpression(e) } // Visitor - 「組み合わせ」 type CombineExpression struct { left, center, right Expression } func (c *CombineExpression) Accept(ev ExpressionVisitor) { ev.VisitCombineExpression(c) } |
それぞれの構造体に設定したAcceptメソッドからExpressionVisitor(クラス)のメソッドへアクセスしています。
訪問先構造体
今回もVIsitorが訪問する構造体を実装します。
1 2 3 4 5 6 7 8 |
// 受け入れ構造体 type ExpressionShow struct { sb strings.Builder } func NewExpressionShow() *ExpressionShow { return &ExpressionShow{strings.Builder{}} } |
別の訪問先を実装したい場合は、別途、構造体を作ることになります。
訪問先構造体のメソッド
今回の訪問先は、顔文字を作成する機能を有します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
func (e *ExpressionShow) VisitEyeExpression(ee *EyeExpression) { e.sb.WriteString(fmt.Sprintf("%s", ee.eye)) } func (e *ExpressionShow) VisitMouthExpression(me *MouthExpression) { e.sb.WriteString(fmt.Sprintf("%s", me.mouth)) } func (e *ExpressionShow) VisitOtherExpression(oe *OtherExpression) { e.sb.WriteString(fmt.Sprintf("%s", oe.other)) } func (e *ExpressionShow) VisitCombineExpression(ce *CombineExpression) { ce.left.Accept(e) ce.center.Accept(e) ce.right.Accept(e) } func (e *ExpressionShow) String() string { return e.sb.String() } |
使ってみよう
ここまで実装したソースコードを使ってみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
func main() { // v(^_^)v e := &CombineExpression{ &OtherExpression{"v("}, &CombineExpression{ &EyeExpression{"^"}, &MouthExpression{"_"}, &EyeExpression{"^"}, }, &OtherExpression{")v"}, } ep := NewExpressionShow() ep.VisitCombineExpression(e) fmt.Println(ep.String()) } |
プログラムを実行します。
1 2 |
$ go run main.go v(^_^)v |
OKですね。
おわりに
今回のソースコードは、ちょっと複雑ですね。
クラスライクなインターフェースとそれをVisitorの共通インターフェースを用意し、Visitor構造体及び訪問先構造体を実装、個別に処理したいメソッド(クラスライクなインターフェースに実装したもの)を用意する感じです。
慣れていないとソースコードも追跡しにくい感じがしますが、使い所はきっとあると思うので、パターンとして知っておいて損はないと思います。
それでは、また!
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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
package main import ( "fmt" "strings" ) // クラスのようなインターフェース type ExpressionVisitor interface { VisitEyeExpression(ee *EyeExpression) VisitMouthExpression(me *MouthExpression) VisitOtherExpression(oe *OtherExpression) VisitCombineExpression(ce *CombineExpression) } // 共通のインターフェース type Expression interface { Accept(ev ExpressionVisitor) } // Visitor -「目」 type EyeExpression struct { eye string } func (e *EyeExpression) Accept(ev ExpressionVisitor) { ev.VisitEyeExpression(e) } // Visitor -「口」 type MouthExpression struct { mouth string } func (e *MouthExpression) Accept(ev ExpressionVisitor) { ev.VisitMouthExpression(e) } // Visitor -「その他」 type OtherExpression struct { other string } func (e *OtherExpression) Accept(ev ExpressionVisitor) { ev.VisitOtherExpression(e) } // Visitor - 「組み合わせ」 type CombineExpression struct { left, center, right Expression } func (c *CombineExpression) Accept(ev ExpressionVisitor) { ev.VisitCombineExpression(c) } // 受け入れ構造体 type ExpressionShow struct { sb strings.Builder } func NewExpressionShow() *ExpressionShow { return &ExpressionShow{strings.Builder{}} } func (e *ExpressionShow) VisitEyeExpression(ee *EyeExpression) { e.sb.WriteString(fmt.Sprintf("%s", ee.eye)) } func (e *ExpressionShow) VisitMouthExpression(me *MouthExpression) { e.sb.WriteString(fmt.Sprintf("%s", me.mouth)) } func (e *ExpressionShow) VisitOtherExpression(oe *OtherExpression) { e.sb.WriteString(fmt.Sprintf("%s", oe.other)) } func (e *ExpressionShow) VisitCombineExpression(ce *CombineExpression) { ce.left.Accept(e) ce.center.Accept(e) ce.right.Accept(e) } func (e *ExpressionShow) String() string { return e.sb.String() } func main() { // v(^_^)v e := &CombineExpression{ &OtherExpression{"v("}, &CombineExpression{ &EyeExpression{"^"}, &MouthExpression{"_"}, &EyeExpression{"^"}, }, &OtherExpression{")v"}, } ep := NewExpressionShow() ep.VisitCombineExpression(e) fmt.Println(ep.String()) } |
コメントを残す
コメントを投稿するにはログインしてください。