こんにちは、KOUKIです。
この記事では、デザインパターンの一つであるStateパターンについて紹介します。
<目次>
デザインパターンまとめ
シチュエーション
State とは、「状態」を意味する英単語です。 Go言語に限らずあらゆるプログラミング言語は、モノ(車とか家とか)をクラスとして表現しますが、State パターンは、 モノではなく「状態」をクラスとして表現するパターンです。
※Go言語ではクラスは存在しないので、構造体やインターフェースがそれらを表現します。
インスタンスの状態によって、振る舞いを変えたい時に便利です。
Stateパターンの適用
PCのON/OFFの状態を、Stateパターンで表現してみましょう。
StateインターフェースとPC構造体
PCのON/OFFの状態を、次ように表現しました。
1 2 3 4 5 6 7 8 9 10 11 |
package main // 状態 type State interface { On(pc *PC) Off(pc *PC) } type PC struct { State State } |
Stateインターフェースには、PC構造体をパラメータにもつOn/Off処理持ちます。
PC構造体は、Stateをパラメータとして持つので、On/Offを呼び出すことができます。
StandbyState
スタンバイ状態を構造体として定義します。
1 2 3 4 5 6 7 8 9 10 |
// PCがスタンバイ状態 type StandbyState struct{} func (s *StandbyState) On(pc *PC) { fmt.Println("Power is already on") } func (s *StandbyState) Off(pc *PC) { fmt.Println("Power is already off") } |
On/Off構造体
On/Off構造体を実装します。
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 |
// Onの状態 type OnState struct { StandbyState } func NewOnState() *OnState { fmt.Println("Power turned on") return &OnState{StandbyState{}} } // Offの状態を格納 func (o *OnState) Off(pc *PC) { fmt.Println("Turning power off...") pc.State = NewOffState() } // Offの状態 type OffState struct { StandbyState } func NewOffState() *OffState { fmt.Println("Power turned off") return &OffState{StandbyState{}} } // Onの状態を格納 func (o *OffState) On(pc *PC) { fmt.Println("Turning power on...") pc.State = NewOnState() } |
PCコンストラクタとメソッド
On/Off構造体のメソッドには、状態を格納する処理(「pc.State = NewOffState()」/「pc.State = NewOnState()」)を入れています。
そのため、PC構造体から以下のようにしてOnState/OffStateのメソッドを呼び出すことができます。
1 2 3 4 5 6 7 8 9 10 11 12 |
// コンストラクタ func NewPC() *PC { return &PC{NewOffState()} // 初期状態はOFF } func (pc *PC) On() { pc.State.On(pc) } func (pc *PC) Off() { pc.State.Off(pc) } |
PC構造体には、Stateインターフェースを実装したOnState/OffState構造体が格納されていて、それらのメソッドの引数としてPC構造体を渡しています。
ちょっとややこしいですね^^;
使ってみよう
ここまで実装したプログラムを使ってみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
func main() { pc := NewPC() pc.On() pc.Off() // もう一度OFFにする pc.Off() // ONにする pc.On() // もう一度ONにする pc.On() } |
1 2 3 4 5 6 7 8 9 10 |
$ go run main.go Power turned off Turning power on... Power turned on Turning power off... Power turned off Power is already off <<<<<<<<< StandbyStateのOffメソッドが呼び出される Turning power on... Power turned on Power is already on <<<<<<<<< StandbyStateのOnメソッドが呼び出される |
OKですね。
PCがOFF状態の時、更にOffメソッドを呼び出すと「Power is already off」が表示されました。これは、StandbyState構造体のOffメソッドが呼ばれたことを示しています。
流れが少し複雑になっているので、整理してみましょう。
- NewPCコンストラクタで、PCインスタンスを生成 -> OffStateインスタンスも生成
- OffStateインスタンスのOnメソッド呼び出し -> OnStateインスタンスを生成し、PCインスタンスに格納
- OnStateインスタンスのOffメソッド呼び出し -> OffStateインスタンスを生成し、PCインスタンスに格納
- OffStateインスタンスのOffメソッド呼び出し -> StandbyStateインスタンスのOffメソッド呼び出し
- 以下略…
実は、OffState構造体にはOnメソッドを、OnState構造体には、Offメソッドを実装していません。その代わり、それぞれのプロパティにStandbyState構造体を持っており、このメソッドを参照しに行います。そのため、上記リストの4の挙動になります。
まとめ
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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
package main import "fmt" // 状態 type State interface { On(pc *PC) Off(pc *PC) } type PC struct { State State } func NewPC() *PC { return &PC{NewOffState()} } func (pc *PC) On() { pc.State.On(pc) } func (pc *PC) Off() { pc.State.Off(pc) } // PCがスタンバイ状態 type StandbyState struct{} func (s *StandbyState) On(pc *PC) { fmt.Println("Power is already on") } func (s *StandbyState) Off(pc *PC) { fmt.Println("Power is already off") } // Onの状態 type OnState struct { StandbyState } func NewOnState() *OnState { fmt.Println("Power turned on") return &OnState{StandbyState{}} } // Offの状態を格納 func (o *OnState) Off(pc *PC) { fmt.Println("Turning power off...") pc.State = NewOffState() } // Offの状態 type OffState struct { StandbyState } func NewOffState() *OffState { fmt.Println("Power turned off") return &OffState{StandbyState{}} } // Onの状態を格納 func (o *OffState) On(pc *PC) { fmt.Println("Turning power on...") pc.State = NewOnState() } func main() { pc := NewPC() pc.On() pc.Off() // もう一度OFFにする pc.Off() // ONにする pc.On() // もう一度ONにする pc.On() } |
コメントを残す
コメントを投稿するにはログインしてください。