こんにちは、KOUKIです。
この記事では、前回に引き続き、デザインパターンの一つであるStateパターンについて紹介します。
<目次>
前回
デザインパターンまとめ
シチュエーション
復習ですが、State パターンは、 モノではなく「状態」をクラスとして表現するパターンです。
※Go言語ではクラスは存在しないので、構造体やインターフェース、変数などがそれらを表現します。
Switch-Based State Machine
今回は、switch文でStateの状態を切り替えるプログラムを作成します。
サンプルとして、任意のキーワードを打ち込み、それが一致したらクリアできる数当てゲームを作りましょう。
State
まずは、Progress / Failed / Clearの3つのState(状態)を実装しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package main import ( "bufio" "fmt" "math/rand" "os" "strconv" "strings" "time" ) type State int const ( Progress State = iota Failed Clear ) |
数当てゲームでは、ゲーム進行中でProgress(進行)、数を間違えたらFailed(失敗)、数を当てたらClear(成功)の3つの状態に遷移します。
Stateパターンを組む時は、プログラムの進行過程でどのような状態になり得るのか、具体的にイメージすることが大切だと思います。
数当てゲーム
数当てゲームを実装します。
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 |
func GuessWhat(answer string, state State, entry strings.Builder) { for { // stateの状態にで変化させる switch state { case Progress: // 標準入力から文字を読み取る r, _, _ := bufio.NewReader(os.Stdin).ReadRune() entry.WriteRune(r) // 答えが一致したらクリア if entry.String() == answer { // State => Clear state = Clear break } // 答えが不一致の場合は失敗 if strings.Index(answer, entry.String()) != 0 { // State => Failed state = Failed } case Failed: fmt.Println("答えが違います。リトライしてください。") entry.Reset() // State => Progress state = Progress case Clear: fmt.Println("おめでとうございます。正解されました!") return } } } |
ご覧の通り、ゲームの進行状況によって、Stateを変化させています。これが、本記事のポイントです。
switch文でStateの分岐を行なっており、状態の変化に伴い、任意の処理を実行できます。使いやすく、目から鱗な実装方法だと思います^^
使ってみよう
ここまで実装したコードを使ってみましょう。
1 2 3 4 5 6 7 8 9 10 11 |
func main() { rand.Seed(time.Now().UnixNano()) // 0 ~ 9までの乱数を作成 answer := strconv.Itoa(rand.Intn(10)) state := Progress entry := strings.Builder{} // ゲーム開始 fmt.Println("数当てゲームを開始します。") GuessWhat(answer, state, entry) } |
実行してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
$ go run main.go 数当てゲームを開始します。 0 答えが違います。リトライしてください。 1 答えが違います。リトライしてください。 2 答えが違います。リトライしてください。 3 答えが違います。リトライしてください。 4 答えが違います。リトライしてください。 5 答えが違います。リトライしてください。 6 答えが違います。リトライしてください。 7 答えが違います。リトライしてください。 8 答えが違います。リトライしてください。 9 おめでとうございます。正解されました! |
よりにもよって9で正解しました^^;でも楽しいですね!
まとめ
これまでに何度か数当てゲームを実装してきましたが、Stateパターンを使ったこのサンプルが一番シンプルに実装できたと思います。Stateパターンは、かなり便利かもしれません。
インスタンスの状態が変化するプログラムを実装する際には、Stateパターンを検討してみてはいかがでしょうか。
それでは、また!
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 ( "bufio" "fmt" "math/rand" "os" "strconv" "strings" "time" ) type State int const ( Progress State = iota Failed Clear ) func GuessWhat(answer string, state State, entry strings.Builder) { for { // stateの状態にで変化させる switch state { case Progress: // 標準入力から文字を読み取る r, _, _ := bufio.NewReader(os.Stdin).ReadRune() entry.WriteRune(r) // 答えが一致したらクリア if entry.String() == answer { // State => Clear state = Clear break } // 答えが不一致の場合は失敗 if strings.Index(answer, entry.String()) != 0 { // State => Failed state = Failed } case Failed: fmt.Println("答えが違います。リトライしてください。") entry.Reset() // State => Progress state = Progress case Clear: fmt.Println("おめでとうございます。正解されました!") return } } } func main() { rand.Seed(time.Now().UnixNano()) // 0 ~ 9までの乱数を作成 answer := strconv.Itoa(rand.Intn(10)) state := Progress entry := strings.Builder{} // ゲーム開始 fmt.Println("数当てゲームを開始します。") GuessWhat(answer, state, entry) } |
コメントを残す
コメントを投稿するにはログインしてください。