デザインパターンを学んでいて、こんな瞬間を経験したことはありませんか?
「StrategyとTemplate Methodは何が違うんだろう? それにCommandはなぜここに入ってくるの?」
3つとも動作を差し替えるように見えるため、混同しやすいパターンです。
まず結論から説明します。
Strategyはアルゴリズム全体を交換し、
Template Methodは骨格を固定したまま一部のステップだけを変更し、
Commandは「実行する動作」をオブジェクトに包んで後から実行します。
この一文を押さえるだけで半分は理解できたも同然です。今日はコードとともに、この3つのパターンを明確に区別します。
3つのパターンは一目でどう違う?
まずは全体像を表で整理します。
| 区分 | Strategyパターン | Template Method | Commandパターン |
|---|---|---|---|
| 核心 | アルゴリズム全体を交換 | 骨格を固定し、一部のステップを交換 | 動作をオブジェクトに包む |
| 再利用の方法 | コンポジション(委譲) | 継承 | コンポジション(委譲) |
| 交換するタイミング | 実行時 | コンパイル時(継承) | 実行時 |
| 代表的な関心事 | 「どう計算するか」 | 「順序は同じで詳細だけ異なるとき」 | 「いつ、何を実行するか」 |
3つのパターンが混同される理由はここにあります。
どれも変化する部分を分離することが目的だからです。
ただし、分離の方法と目的は異なります。順に見ていきましょう。
Strategyパターンはアルゴリズム全体を差し替える
Strategyパターンは、同じ仕事を行う複数の方法をそれぞれ独立したオブジェクトにし、必要に応じて差し替える方式です。
決済手段を考えると分かりやすいでしょう。
カード決済、KakaoPay、銀行振込。目的(決済)は同じでも方法が異なります。
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)で委譲するのがポイントです。
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語だけ覚えておけば、もう迷いません。今日も楽しく学んでいきましょう!

