saeki’s blog

The limits of my code mean the limits of my world.

GoFデザインパターン ~Strategyパターン~

Strategyパターンとは

ある問題に対して複数の解法が存在する場合、コンテキストに合わせてアルゴリズムのスイッチングを簡単に行えるようにするためのパターン。Strategyは「戦略」という意味。

Strategyパターンにおける役割

name description
Strategy アルゴリズムを利用するためのインターフェース。
ConcreteStrategy Strategyインターフェースを継承し、アルゴリズムの具体的な実装を行う。
Context 文脈に沿ってStrategyを呼び出す役。Strategyは外部からContextに注入し、ContextとStrategyは疎結合になるようにする。

GoでStrategyパターンの簡単な枠組みを実装してみる

$ tree ./
├── context.go
├── main.go
└── strategy
    ├── strategy.go
    ├── strategy_alpha.go
    └── strategy_beta.go

Strategyパッケージ

package strategy

type Strategy interface {
    Call()
}

type AlphaStrategy struct{}

func (*AlphaStrategy) Call() {
    // Do something
}

type BetaStrategy struct{}

func (*BetaStrategy) Call() {
    // Do something
}

Strategy interface がアルゴリズムを実行するための窓口になる。アルゴリズムを利用する側は Strategy interfaceにのみ依存する。
AlphaStrategy BetaStrategy はそれぞれ Strategy interface を継承していて、アルゴリズムの具体的な実装を行う。

Mainパッケージ

package main

import (
    "os"

    "github.com/saekis/go-design-pattern/8_strategy/strategy"
)

func main() {
    var s strategy.Strategy

    switch os.Args[1] {
    case "alpha":
        s = &strategy.AlphaStrategy{}
    case "beta":
        s = &strategy.BetaStrategy{}
    default:
        return
    }

    Context{s}.Exec()
}

type Context struct {
    strategy strategy.Strategy
}

func (c *Context) Exec() {
    c.strategy.Call()
}

Context.Exec() はアルゴリズムを利用するが、実際のアルゴリズムの処理は注入されたStrategyに委譲する。こうすることで、アルゴリズムを利用する文脈とアルゴリズムの実装を疎結合にすることができるので、アルゴリズムのスイッチングが容易になり、テスタビリティの向上が期待できる。

github.com