ソフトウェア設計

Strategy vs Template Method vs Commandの違い

デザインパターンを学んでいて、こんな瞬間を経験したことはありませんか?

読了 5 分
Strategy vs Template Method vs Commandの違いのカバー画像

デザインパターンを学んでいて、こんな瞬間を経験したことはありませんか?

「StrategyとTemplate Methodは何が違うんだろう? それにCommandはなぜここに入ってくるの?」

3つとも動作を差し替えるように見えるため、混同しやすいパターンです。

まず結論から説明します。

Strategyはアルゴリズム全体を交換し、

Template Methodは骨格を固定したまま一部のステップだけを変更し、

Commandは「実行する動作」をオブジェクトに包んで後から実行します。

この一文を押さえるだけで半分は理解できたも同然です。今日はコードとともに、この3つのパターンを明確に区別します。


3つのパターンは一目でどう違う?

まずは全体像を表で整理します。

区分 Strategyパターン Template Method Commandパターン
核心 アルゴリズム全体を交換 骨格を固定し、一部のステップを交換 動作をオブジェクトに包む
再利用の方法 コンポジション(委譲) 継承 コンポジション(委譲)
交換するタイミング 実行時 コンパイル時(継承) 実行時
代表的な関心事 「どう計算するか」 「順序は同じで詳細だけ異なるとき」 「いつ、何を実行するか」

3つのパターンが混同される理由はここにあります。

どれも変化する部分を分離することが目的だからです。

ただし、分離の方法と目的は異なります。順に見ていきましょう。


Strategyパターンはアルゴリズム全体を差し替える

Strategyパターンは、同じ仕事を行う複数の方法をそれぞれ独立したオブジェクトにし、必要に応じて差し替える方式です。

決済手段を考えると分かりやすいでしょう。

カード決済、KakaoPay、銀行振込。目的(決済)は同じでも方法が異なります。

Strategyパターンによるアルゴリズムの差し替え
Strategyパターンはこのように全体を差し替える構造です
protocol PayStrategy {
    func pay(_ amount: Int) -> String
}
struct CardPay: PayStrategy {
    func pay(_ amount: Int) -> String { "カードで \(amount)ウォン決済" }
}
struct KakaoPay: PayStrategy {
    func pay(_ amount: Int) -> String { "KakaoPayで \(amount)ウォン決済" }
}

var strategy: PayStrategy = CardPay()
print(strategy.pay(10000))
// 出力:カードで 10000ウォン決済

要点は、strategy変数を実行時にKakaoPay()へ変更すると、動作全体が差し替わることです。

継承ではなく、コンポジション(composition)で委譲するのがポイントです。

決済Strategyのコードを書くと委譲構造がよく分かる
決済Strategyのコードを書くと委譲構造がよく分かります

Template Methodは骨格を残して一部だけを変える

Template Methodは少し性質が異なります。

全体の流れの順序は固定し、その中の一部のステップだけをサブクラスが実装します。

ラーメンを作る手順を思い浮かべてください。湯を沸かす→具材を入れる→完成。順序は同じでも、「具材を入れる」ステップだけが変わります。

class Ramen {
    func cook() {           // これがTemplate Method
        boilWater()
        addIngredients()    // このステップだけサブクラスで差し替え
        print("完成!")
    }
    func boilWater() { print("湯を沸かす") }
    func addIngredients() { print("基本の具材") }
}
class CheeseRamen: Ramen {
    override func addIngredients() { print("チーズを追加") }
}
CheeseRamen().cook()
// 出力:湯を沸かす / チーズを追加 / 完成!

Strategyとの決定的な違いは、継承を使い、全体ではなく一部のステップだけを変更する点です。

フロー(cook)の主導権は親クラスが握ります。


Commandパターンは実行する動作そのものを包む

Commandは前の2つとは関心事がまったく異なります。

どう計算するかではなく、この動作をオブジェクトにして後で実行、取り消し、キューへの追加を行うことが目的です。

リモコンのボタンを思い浮かべると簡単です。ボタンは「電気をつける」という命令をオブジェクトとして保持し、押したときに実行します。

protocol Command { func execute() }
struct LightOn: Command {
    func execute() { print("電気をつける") }
}

let button: Command = LightOn()
button.execute()   // 実行するタイミングを自分で決める
// 出力:電気をつける

リクエストをオブジェクトで包むため、undo、ログ記録、作業キューなどを自然に追加できます。

Strategyは方法を選ぶパターン、Commandはリクエストを保存して扱うパターンと整理すると分かりやすいでしょう。


いつ使い、いつ避けるべきか

実務では次の基準で選びます。

  • Strategyパターン:同じ目的のアルゴリズムが複数あり、実行時に切り替える必要があるとき(ソート方式、割引ポリシー、決済手段)
  • Template Method:処理順序は常に同じで、一部のステップだけが異なるとき(データ解析の流れ、ゲームのターン進行)
  • Command:実行の延期、取り消し・再実行・キューイングが必要なとき(元に戻す操作、ジョブスケジューラ)

逆に、避けるべきサインもあります。

分岐が2、3個だけで今後増えないなら、無理にパターンを導入しないでください。単純なifの方が読みやすくなります。

特にTemplate Methodは継承に依存する構造なので、柔軟性が重要なら、まずStrategy(コンポジション)を検討する方が安全です。


面接ではこう聞かれます

Q. StrategyとTemplate Methodの最大の違いは?

Strategyはコンポジション(委譲)でアルゴリズム全体を実行時に交換し、Template Methodは継承で骨格を固定したまま一部のステップだけをオーバーライドします。柔軟性はStrategy、フローの制御はTemplate Methodが優れています。

Q. CommandはStrategyとどこが違う?

Strategyはどの方法で実行するかの選択に集中し、Commandはリクエスト自体をオブジェクトに包んで、undo・キューイング・ロギングなどの操作を可能にします。関心事がアルゴリズム選択か、リクエスト管理かの違いです。


3つのパターンは似て見えても、何をなぜ分離するのかを基準にすれば明確に区別できます。

Strategyは方法、Template Methodは順序の中の空欄、Commandはリクエストそのもの。この3語だけ覚えておけば、もう迷いません。今日も楽しく学んでいきましょう!

あわせて読みたい