最終更新:2020/05/11
この記事の内容は
を参考にGo言語に置き換えた内容になっております。
わかりにくい箇所は私の責任であり、java言語で学ぶデザインパターンのせいではありません。
目次
- Strategyパターンとは
- Strategyパターンの構成
- サンプルコード
- サンプルコードの説明
- サンプルコードの実行
1. Strategyパターンとは
Strategyパターンは、アルゴリズム部分を切り替えるのを容易にするパターンです。
2. Strategyパターンの構成
Strategyパターンは以下の役割で構成します。
Strategy
戦略を利用するための役割をもちます。
Strategyはインターフェースで定めます。
ConcreateStrategy
Strategyインターフェースを具体的に実装します。
Context
Strategyを利用する役割を担います。
ConcreateStrategyのインスタンスを持って、必要に応じて利用します。
3. サンプルコード
package strategy
import (
"math/rand"
)
type Hand struct {
HandValue int
}
func NewHand(num int) Hand {
a := num % 3
return Hand{
HandValue: a,
}
}
// Strategy
type Strategy interface {
NextHand() Hand
Study(bool)
}
// ConcreateStrategy
type WinningStrategy struct {
Rand *rand.Rand
Hand Hand
Won bool
}
func NewWinningStrategy(num int64) Strategy {
strategy := &WinningStrategy{
Rand: rand.New(rand.NewSource(num)),
Hand: NewHand(int(num)),
Won: false,
}
return strategy
}
func (s *WinningStrategy) NextHand() Hand {
if !s.Won {
s.Hand = NewHand(s.Rand.Int())
}
return s.Hand
}
func (s *WinningStrategy) Study(win bool) {
s.Won = win
}
// ConcreateStrategy
type SecondStrategy struct {
Rand *rand.Rand
Hand Hand
Won bool
}
func NewSecondStrategy(num int64) Strategy {
strategy := &SecondStrategy{
Rand: rand.New(rand.NewSource(num)),
Hand: NewHand(int(num)),
Won: false,
}
return strategy
}
func (s *SecondStrategy) NextHand() Hand {
if s.Won {
s.Hand = NewHand(s.Rand.Int() + 1)
}
return s.Hand
}
func (s *SecondStrategy) Study(win bool) {
s.Won = !win
}
// Context
type Player struct {
Name string
Stg Strategy
}
func NewPlayer(Name string, stra Strategy) Player {
player := Player{
Name: Name,
Stg: stra,
}
return player
}
func (p *Player) NextHand() Hand {
return p.Stg.NextHand()
}
func (p *Player) win() {
p.Stg.Study(true)
}
4. サンプルコードの説明
上記のコードの構成は以下の通りです。
Strategy
Strategyの役割は、戦略を利用するためのメソッドを集めて定義することです。
サンプルコードだとStrategyインターフェースが担います。
// Strategy
type Strategy interface {
NextHand() Hand
Study(bool)
}
ConcreateStrategy
ConcreateStrategyはStrategyを具体的に実装します。
サンプルコードだとWinningStrategy構造体とNewSecondStrategy構造体が役割を担います。
初期化時に、Strategyインターフェースを返すのがポイントです。
func NewWinningStrategy(num int64) Strategy {
strategy := &WinningStrategy{
Rand: rand.New(rand.NewSource(num)),
Hand: NewHand(int(num)),
Won: false,
}
return strategy
}
func NewSecondStrategy(num int64) Strategy {
strategy := &SecondStrategy{
Rand: rand.New(rand.NewSource(num)),
Hand: NewHand(int(num)),
Won: false,
}
return strategy
}
Context
ContextはStrategyを利用する役割を担います。
ConcreateStrategyのインスタンスを持って、必要に応じて利用します。
サンプルコードだとPlayer構造体が役割を担います。
type Player struct {
Name string
Stg Strategy
}
func NewPlayer(Name string, stra Strategy) Player {
player := Player{
Name: Name,
Stg: stra,
}
return player
}
初期化時に、Strategyインターフェースを受け取るのがポイントです。
5. サンプルコードの実行
上記のコードをmain関数で呼び出します。
package main
import (
"fmt"
"github.com/java-lang-programming/marsa/strategy"
)
func main() {
player1 := strategy.NewPlayer("Taro", strategy.NewWinningStrategy(1))
player2 := strategy.NewPlayer("Sato", strategy.NewSecondStrategy(1))
result1 := player1.NextHand()
result2 := player2.NextHand()
fmt.Println(result1.HandValue)
fmt.Println(result2.HandValue)
}
NewPlayerの第二引数で、NewWinningStrategyとNewSecondStrategyの両方を受け取れています。
player1 := strategy.NewPlayer("Taro", strategy.NewWinningStrategy(1))
player2 := strategy.NewPlayer("Sato", strategy.NewSecondStrategy(1))
この理由は、引数がStrategyインタフェースなので、Strategyインタフェースを利用しているWinningStrategyとSecondStrategyが使えるからです。
こうすることでPleyerは、引数がWinningStrategyかSecondStrategyを意識しないでStrategyのメソッドを呼び出して使うことができます。
実行すると以下が出力されます。
# go run main.go
2
1