Javaの戦略パターン:交換可能なアルゴリズムによるオブジェクト動作の合理化
別名
- ポリシー
戦略デザインパターンの目的
Javaでアルゴリズムのファミリーを定義し、それぞれをカプセル化し、交換可能にすることで、戦略デザインパターンを使用してソフトウェア開発を強化します。戦略により、アルゴリズムを使用するクライアントとは独立してアルゴリズムを変更できます。
実際の例を用いた戦略パターンの詳細な説明
実世界の例
Javaにおける戦略デザインパターンの実用的な実世界の例は、アルゴリズムの柔軟性が最重要なカーナビゲーションシステムで明らかです。異なるナビゲーションアルゴリズム(最短ルート、最速ルート、景観ルートなど)を使用して、ある場所から別の場所への最適なパスを決定できます。各アルゴリズムは、ルートを計算するための特定の戦略をカプセル化します。ユーザー(クライアント)は、ナビゲーションシステム自体を変更することなく、これらのアルゴリズムを自分の好みに基づいて切り替えることができます。これにより、同じシステム内で柔軟で交換可能なナビゲーション戦略が可能になります。
簡単な言葉で
戦略パターンは、実行時に最適なアルゴリズムを選択できるようにします。
Wikipediaによると
コンピュータプログラミングでは、戦略パターン(ポリシーパターンとも呼ばれる)は、実行時にアルゴリズムを選択できるようにする振る舞いソフトウェア設計パターンです。
Javaにおける戦略パターンのプログラム例
ドラゴン退治は危険な仕事です。経験を積むことで、それは容易になります。ベテランドラゴン退治士は、さまざまなタイプのドラゴンに対して異なる戦闘戦略を開発しました。
Javaで`DragonSlayingStrategy`インターフェースを実装する方法を調べ、さまざまな戦略パターンのアプリケーションを実演してみましょう。
@FunctionalInterface
public interface DragonSlayingStrategy {
void execute();
}
@Slf4j
public class MeleeStrategy implements DragonSlayingStrategy {
@Override
public void execute() {
LOGGER.info("With your Excalibur you sever the dragon's head!");
}
}
@Slf4j
public class ProjectileStrategy implements DragonSlayingStrategy {
@Override
public void execute() {
LOGGER.info("You shoot the dragon with the magical crossbow and it falls dead on the ground!");
}
}
@Slf4j
public class SpellStrategy implements DragonSlayingStrategy {
@Override
public void execute() {
LOGGER.info("You cast the spell of disintegration and the dragon vaporizes in a pile of dust!");
}
}
そして、こちらが対戦相手に基づいて戦闘戦略を選択できる強力な`DragonSlayer`です。
public class DragonSlayer {
private DragonSlayingStrategy strategy;
public DragonSlayer(DragonSlayingStrategy strategy) {
this.strategy = strategy;
}
public void changeStrategy(DragonSlayingStrategy strategy) {
this.strategy = strategy;
}
public void goToBattle() {
strategy.execute();
}
}
最後に、`DragonSlayer`の動作をご紹介します。
@Slf4j
public class App {
private static final String RED_DRAGON_EMERGES = "Red dragon emerges.";
private static final String GREEN_DRAGON_SPOTTED = "Green dragon spotted ahead!";
private static final String BLACK_DRAGON_LANDS = "Black dragon lands before you.";
public static void main(String[] args) {
// GoF Strategy pattern
LOGGER.info(GREEN_DRAGON_SPOTTED);
var dragonSlayer = new DragonSlayer(new MeleeStrategy());
dragonSlayer.goToBattle();
LOGGER.info(RED_DRAGON_EMERGES);
dragonSlayer.changeStrategy(new ProjectileStrategy());
dragonSlayer.goToBattle();
LOGGER.info(BLACK_DRAGON_LANDS);
dragonSlayer.changeStrategy(new SpellStrategy());
dragonSlayer.goToBattle();
// Java 8 functional implementation Strategy pattern
LOGGER.info(GREEN_DRAGON_SPOTTED);
dragonSlayer = new DragonSlayer(
() -> LOGGER.info("With your Excalibur you severe the dragon's head!"));
dragonSlayer.goToBattle();
LOGGER.info(RED_DRAGON_EMERGES);
dragonSlayer.changeStrategy(() -> LOGGER.info(
"You shoot the dragon with the magical crossbow and it falls dead on the ground!"));
dragonSlayer.goToBattle();
LOGGER.info(BLACK_DRAGON_LANDS);
dragonSlayer.changeStrategy(() -> LOGGER.info(
"You cast the spell of disintegration and the dragon vaporizes in a pile of dust!"));
dragonSlayer.goToBattle();
// Java 8 lambda implementation with enum Strategy pattern
LOGGER.info(GREEN_DRAGON_SPOTTED);
dragonSlayer.changeStrategy(LambdaStrategy.Strategy.MELEE_STRATEGY);
dragonSlayer.goToBattle();
LOGGER.info(RED_DRAGON_EMERGES);
dragonSlayer.changeStrategy(LambdaStrategy.Strategy.PROJECTILE_STRATEGY);
dragonSlayer.goToBattle();
LOGGER.info(BLACK_DRAGON_LANDS);
dragonSlayer.changeStrategy(LambdaStrategy.Strategy.SPELL_STRATEGY);
dragonSlayer.goToBattle();
}
}
プログラム出力
13:06:36.631 [main] INFO com.iluwatar.strategy.App -- Green dragon spotted ahead!
13:06:36.634 [main] INFO com.iluwatar.strategy.MeleeStrategy -- With your Excalibur you sever the dragon's head!
13:06:36.634 [main] INFO com.iluwatar.strategy.App -- Red dragon emerges.
13:06:36.634 [main] INFO com.iluwatar.strategy.ProjectileStrategy -- You shoot the dragon with the magical crossbow and it falls dead on the ground!
13:06:36.634 [main] INFO com.iluwatar.strategy.App -- Black dragon lands before you.
13:06:36.634 [main] INFO com.iluwatar.strategy.SpellStrategy -- You cast the spell of disintegration and the dragon vaporizes in a pile of dust!
13:06:36.634 [main] INFO com.iluwatar.strategy.App -- Green dragon spotted ahead!
13:06:36.634 [main] INFO com.iluwatar.strategy.App -- With your Excalibur you severe the dragon's head!
13:06:36.634 [main] INFO com.iluwatar.strategy.App -- Red dragon emerges.
13:06:36.635 [main] INFO com.iluwatar.strategy.App -- You shoot the dragon with the magical crossbow and it falls dead on the ground!
13:06:36.635 [main] INFO com.iluwatar.strategy.App -- Black dragon lands before you.
13:06:36.635 [main] INFO com.iluwatar.strategy.App -- You cast the spell of disintegration and the dragon vaporizes in a pile of dust!
13:06:36.635 [main] INFO com.iluwatar.strategy.App -- Green dragon spotted ahead!
13:06:36.637 [main] INFO com.iluwatar.strategy.LambdaStrategy -- With your Excalibur you severe the dragon's head!
13:06:36.637 [main] INFO com.iluwatar.strategy.App -- Red dragon emerges.
13:06:36.637 [main] INFO com.iluwatar.strategy.LambdaStrategy -- You shoot the dragon with the magical crossbow and it falls dead on the ground!
13:06:36.637 [main] INFO com.iluwatar.strategy.App -- Black dragon lands before you.
13:06:36.637 [main] INFO com.iluwatar.strategy.LambdaStrategy -- You cast the spell of disintegration and the dragon vaporizes in a pile of dust!
Javaで戦略パターンを使用する場合
戦略パターンを使用する場合
- オブジェクト内でアルゴリズムの異なるバリアントを使用する必要があり、実行時にアルゴリズムを切り替えたい場合。
- 振る舞いだけが異なる複数の関連クラスがある場合。
- アルゴリズムがクライアントが知るべきではないデータを使用する場合。
- クラスが多くの振る舞いを定義し、それらが操作に複数の条件文として現れる場合。
戦略パターン Javaチュートリアル
Javaにおける戦略パターンの実際のアプリケーション
- Javaの`java.util.Comparator`インターフェースは、戦略パターンの一般的な例です。
- GUIフレームワークでは、レイアウトマネージャー(JavaのAWTやSwingなど)は戦略です。
戦略パターンの利点とトレードオフ
利点
- 関連するアルゴリズムのファミリーが再利用されます。
- 振る舞いを拡張するためのサブクラス化の代替手段。
- 目的の振る舞いを選択するための条件文を回避します。
- クライアントがアルゴリズムの実装を選択できるようにします。
トレードオフ
- クライアントは異なる戦略を認識している必要があります。
- オブジェクト数の増加。
関連するJavaデザインパターン
- デコレータ:インターフェースを変更せずにオブジェクトを強化しますが、アルゴリズムよりも責務に関心があります。
- 状態:構造は似ていますが、交換可能なアルゴリズムではなく、状態依存の振る舞いを表すために使用されます。