【デザインパターン】Strategyパターンについて学習したことの備忘録

# はじめに
Strategyパターンについて学習したことの備忘録です。

# 概要

Strategy パターンは、アルゴリズムや処理の一部をカプセル化し、それらを相互に置き換え可能にするデザインパターンである。異なるアルゴリズムを必要に応じて柔軟に切り替えることができ、条件分岐に依存せずに動作を変更できるように設計する。これにより、特定の機能に対して複数のアルゴリズムを持つ場合、その実装を外部化して管理することが可能となる。
つまり、「やりたいこと」に対して、その「実現方法」が複数ある場合に、その選択、拡張、修正をやりやすくするためのパターン。

# 利用目的

- 実行時に異なるアルゴリズムを切り替える必要がある場合に利用する。
- クラスが複数の異なる動作を持つ場合に、条件分岐を使わずに動作をそれぞれ独立したクラスに分離する。
- アルゴリズムや処理を簡単に追加、変更、削除できるようにし、コードの拡張性を高めることが目的である。

# メリット

- **柔軟性**: アルゴリズムを実行時に容易に切り替えられる。
- **保守性**: それぞれのアルゴリズムが独立しているため、変更が他の部分に影響を与えることが少ない。
- **拡張性**: 新しいアルゴリズムや処理方法を追加する際に、既存のコードを変更する必要がない。

# 注意点

- クラスの数が増えるため、管理が複雑になる可能性がある。
- Strategy の切り替えを適切に管理しなければ、予期しない動作が発生する可能性がある。

# 実装例

次に、`Strategy`パターンを Java で実装した例を示す。以下は、異なる割引戦略を商品に適用する例である。

```java:DiscountStrategy.java
// 割引のインターフェース
interface DiscountStrategy {
    double applyDiscount(double price);
}
```

```java:NoDiscountStrategy.java
// 割引なしの戦略
public class NoDiscountStrategy implements DiscountStrategy {
    @Override
    public double applyDiscount(double price) {
        return price;
    }
}

```

```java:PercentageDiscountStrategy.java
// パーセント割引の戦略
class PercentageDiscountStrategy implements DiscountStrategy {
    private double percentage;

    public PercentageDiscountStrategy(double percentage) {
        this.percentage = percentage;
    }

    @Override
    public double applyDiscount(double price) {
        return price - (price * percentage / 100);
    }
}
```
```java:FixedDiscountStrategy.java
// 固定額割引の戦略
class FixedDiscountStrategy implements DiscountStrategy {
    private double discountAmount;

    public FixedDiscountStrategy(double discountAmount) {
        this.discountAmount = discountAmount;
    }

    @Override
    public double applyDiscount(double price) {
        return price - discountAmount;
    }
}
```

```java:Product.java
// 商品クラス
class Product {
    private String name;
    private double price;
    private DiscountStrategy discountStrategy;

    public Product(String name, double price, DiscountStrategy discountStrategy) {
        this.name = name;
        this.price = price;
        this.discountStrategy = discountStrategy;
    }

    public void setDiscountStrategy(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    public double getPrice() {
        return discountStrategy.applyDiscount(price);
    }

}
```

```java:App.java
// 使用例
// 使用するクラスにおいて、Strategyインターフェースの変数を保持する（コンポジション）ことで、処理を委譲している。
public class App {
    public static void main(String[] args) {
        // 割引なしの製品
        Product product = new Product("Laptop", 1000, new NoDiscountStrategy());
        System.out.println("Price with no discount: " + product.getPrice()); // 1000.0

        // パーセント割引を適用
        product.setDiscountStrategy(new PercentageDiscountStrategy(10));
        System.out.println("Price with 10% discount: " + product.getPrice());  // 900.0

        // 固定額割引を適用
        product.setDiscountStrategy(new FixedDiscountStrategy(100));
        System.out.println("Price with $100 discount: " + product.getPrice());  // 900.0
    }
}
```

# クラス図
![strategy_class_diagram.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3845328/d8f96cfa-e578-60e5-ba11-27f0c15bb628.jpeg)