はじめに:Strategyパターンはなぜ必要なのか?
Javaで開発をしていると、「処理は似ているけれど、中身だけ変えたい」という場面に必ず出会います。
例えば…
- 割引方法を切り替えたい
- 並び替えロジックを状況に応じて変えたい
- 支払い方法(クレジット・ポイント・現金)を切り替えたい
- ファイルの処理方法(コピー・削除・圧縮)を変えたい
こうしたケースで使われるのが Strategyパターン(ストラテジーパターン) です。
Strategyパターンとは、
「アルゴリズム(処理)を入れ替えられるようにするためのデザインパターン」
のこと。
しかし、従来の Strategy パターンは
「インターフェース + 複数の具象クラス」
という構造になりがちで、規模が大きくなるとクラス数が増えて大変…
そこで、Java8 以降で使える ラムダ式(匿名関数) を活用すると、
Strategyパターンの実装は劇的にスマートになります。
本記事では、プログラミング初心者や Java の学習者にも分かるように、
「ラムダ式 × Strategyパターン」 を実例満載で丁寧に解説していきます。
さらに、
- 具体的な実装例
- 応用パターン
- 現場での使われ方
- Java がこのパターンと相性抜群な理由
も合わせて解説します。
最後には学習ロードマップとして、
- 絶対にJavaプログラマーになりたい人へ。(https://amzn.asia/d/3E1CYbv)
- サイゼントアカデミー(https://academy.cyzennt.co.jp)
も紹介しています。
それではさっそく始めましょう。
【第1章】Strategyパターンとは?
Strategyパターンは、デザインパターンの中でも非常に有名で、初学者が必ず理解すべき重要パターンのひとつです。
Strategyパターンの目的はシンプルです。
▼ Strategyパターンの目的
- アルゴリズム(処理)を「ひとつのクラスに固定」しない
- アルゴリズムを自由に差し替えることができる
- 変更が必要な時、ほかのクラスに影響を与えない
よくある設計の失敗例として、「if 文で条件分岐を増やしすぎる」ケースがあります。
|
1 2 3 4 5 6 7 8 |
if (type.equals("add")) { // 足し算処理 } else if (type.equals("sub")) { // 引き算処理 } else if (type.equals("mul")) { // 掛け算処理 } |
このようなコードは、
- 分岐が増えると読みにくくなる
- 新しい処理を追加するとき if が増える
- テストしにくい
- 修正に弱い
というデメリットがあります。
そこで Strategy パターンを使うと、
「変更される可能性のある処理」を
ひとつの共通インターフェースでまとめる
という構造にできます。
【第2章】従来のStrategyパターン(クラスが多い…)
まずは従来の書き方を確認しておきましょう。
|
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 |
interface Strategy { int execute(int a, int b); } class AddStrategy implements Strategy { public int execute(int a, int b) { return a + b; } } class SubStrategy implements Strategy { public int execute(int a, int b) { return a - b; } } class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public int execute(int a, int b) { return strategy.execute(a, b); } } |
使う側はこうなります。
|
1 2 3 |
Context context = new Context(new AddStrategy()); System.out.println(context.execute(10, 20)); |
▼ 従来方式の欠点
- クラスが増えすぎて管理が大変
- Strategy の数だけ新しいクラスを作る必要がある
- 初心者には理解しづらい
- コードが長くなる
【第3章】Java8以降:ラムダ式で Strategy が劇的にスマートに!
Java 8 以降では ラムダ式(匿名関数) が使えるようになりました。
ラムダ式は、
- 関数を「その場で定義して渡す」
- インターフェースを「実装するクラスを作らなくても良い」
という特徴があり、Strategy と非常に相性が良いです。
【第4章】ラムダ式での Strategy パターン(基本形)
まずは最小のコード。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@FunctionalInterface interface Strategy { int execute(int a, int b); } class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public int execute(int a, int b) { return strategy.execute(a, b); } } |
使う側:
|
1 2 3 4 5 6 |
Context add = new Context((a, b) -> a + b); Context sub = new Context((a, b) -> a - b); System.out.println(add.execute(10, 20)); // 30 System.out.println(sub.execute(10, 20)); // -10 |
▼ ラムダ式 Strategy のメリット
- クラスが不要
- その場で振る舞いを定義できる
- 可読性が高くなる
- 柔軟で拡張しやすい
Java の強みである「関数型インターフェース」と「ラムダ式」が組み合わさったことで、
Strategy パターンはより簡潔になりました。
【第5章】実務で使われる「Map × Strategy」
業務システムでは、特定のキーに応じて処理を切り替えることが多いです。
そのとき便利なのがこのスタイル。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import java.util.Map; @FunctionalInterface interface Strategy { int exec(int a, int b); } class Calculator { private static final Map<String, Strategy> strategies = Map.of( "add", (a, b) -> a + b, "sub", (a, b) -> a - b, "mul", (a, b) -> a * b ); public static int calculate(String key, int a, int b) { return strategies.get(key).exec(a, b); } } |
使う側:
|
1 2 |
System.out.println(Calculator.calculate("mul", 3, 5)); // 15 |
▼ 特徴
- if / switch をゼロにできる
- 新しい戦略追加が超簡単
- Map の中身を見るだけで「どんな戦略があるか」分かる
実務で非常に好まれる書き方です。
【第6章】Strategyパターンの応用例
1:ファイル処理を Strategy 化
|
1 2 3 4 5 6 7 8 9 10 |
@FunctionalInterface interface FileStrategy { void handle(Path path) throws Exception; } FileStrategy copy = p -> Files.copy(p, Path.of("backup.txt")); FileStrategy delete = p -> Files.delete(p); copy.handle(Path.of("data.txt")); |
2:バリデーションを Strategy 化
|
1 2 3 4 5 6 7 8 |
@FunctionalInterface interface Validator { boolean validate(String input); } Validator emailValidator = s -> s.contains("@"); Validator numberValidator = s -> s.matches("\\d+"); |
3:Spring Boot と Strategy
Spring ではよく「業務ロジックの切り替え」「優先度処理」で Strategy が使われます。
ラムダ式と組み合わせることで、さらにコードが見やすくなります。
【第7章】Java が Strategy パターンと相性抜群な理由
Java の強み
- マルチスレッドが強い
- JVM がエラーに強く堅牢
- 関数型インターフェースが強力
- ラムダ式で柔軟な実装ができる
特に Java 8 以降のアップデートで、
関数型の機能が大幅に強化されたため、
Strategy パターンのような「振る舞いを渡すパターン」と相性が良くなりました。
【第8章】最も美しい Strategy 実装(完成形)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@FunctionalInterface interface Strategy { int apply(int a, int b); } var strategies = Map.of( "add", (Strategy)( (a, b) -> a + b ), "sub", (Strategy)( (a, b) -> a - b ), "mul", (Strategy)( (a, b) -> a * b ) ); System.out.println(strategies.get("mul").apply(3, 4)); |
これで 無駄なクラスはゼロ。
Strategy の「最も簡潔な形」と言えるでしょう。
【第9章】Java学習の次のステップ
Strategyパターンは Java において必ず通る道です。
しかし、Java を仕事にできるレベルに上げるには、
まだまだ多くの学習が必要です。
そんなあなたに2つの選択肢があります。
📘 自己学習で力をつけたい人へ
まずは文章で体系的に学ぶのがおすすめです。
👉 絶対にJavaプログラマーになりたい人へ。
https://amzn.asia/d/3E1CYbv
🎓 実務レベルのコードレビュー・転職サポートを受けたい人へ
自己学習で挫折しそう…
コードレビューをしてほしい…
転職もサポートしてほしい…
そんな人にはコレ。
👉 サイゼントアカデミー
https://academy.cyzennt.co.jp
Java に特化した学習環境で、
「初心者 → プログラマーへの転職」をサポートしています。
【まとめ】
本記事では、
- Strategyパターンの基本
- 従来の実装方法の課題
- ラムダ式によるスマート実装
- 実務で使える Map × Strategy
- 具体的な応用例
- Java が Strategy と相性が良い理由
- 学習の次のステップ
まで徹底的に解説してきました。
ラムダ式を使うことで、Strategyパターンはより強力で、
より読みやすく、より保守しやすくなります。
今後の Java 開発でも非常に役に立つ考え方です。
ぜひ、あなたのコードにも活かしてみてください!

コメント