Skip to content

ストラテジーパターン

公開日:November 17, 2024更新日:November 28, 2024
TypeScriptDesign pattern📄

ストラテジーパターン

ストラテジーパターン(Strategy Pattern) は、アルゴリズムや処理の一部をコンテキストから分離して、動的に選択・変更できるようにするデザインパターンです。このパターンは、特定の動作をクラスとして定義し、それらを切り替えることで、異なる戦略(処理)を実行できる柔軟な設計を提供します。

ストラテジーパターンは、同じ動作を異なるアルゴリズムで実装する必要がある場合に有効です。例えば、支払い方法の選択や、ソートアルゴリズムの切り替えなどで利用されます。

TypeScriptでのストラテジーパターンの実装

以下に、TypeScriptでストラテジーパターンを実装する例を示します。ここでは、ショッピングカートにおける異なる支払い方法(クレジットカード、PayPal)を選択する例を紹介します。

支払い方法の例

typescript
// PaymentStrategy インターフェース
interface PaymentStrategy {
  pay(amount: number): void;
}

// クレジットカードによる支払いの実装
class CreditCardPayment implements PaymentStrategy {
  private name: string;
  private cardNumber: string;

  constructor(name: string, cardNumber: string) {
    this.name = name;
    this.cardNumber = cardNumber;
  }

  pay(amount: number): void {
    console.log(`${amount} 円をクレジットカードで支払いました(カード番号: ${this.cardNumber})`);
  }
}

// PayPalによる支払いの実装
class PayPalPayment implements PaymentStrategy {
  private email: string;

  constructor(email: string) {
    this.email = email;
  }

  pay(amount: number): void {
    console.log(`${amount} 円をPayPalで支払いました(アカウント: ${this.email})`);
  }
}

// ショッピングカートクラス
class ShoppingCart {
  private items: number[] = [];
  private paymentStrategy: PaymentStrategy;

  addItem(price: number): void {
    this.items.push(price);
  }

  setPaymentStrategy(paymentStrategy: PaymentStrategy): void {
    this.paymentStrategy = paymentStrategy;
  }

  checkout(): void {
    const totalAmount = this.items.reduce((sum, price) => sum + price, 0);
    this.paymentStrategy.pay(totalAmount);
  }
}

// 実際の使用例
const cart = new ShoppingCart();
cart.addItem(500);
cart.addItem(1500);

// クレジットカードで支払う場合
cart.setPaymentStrategy(new CreditCardPayment('山田太郎', '1234-5678-9012-3456'));
cart.checkout(); // "2000 円をクレジットカードで支払いました(カード番号: 1234-5678-9012-3456)"

// PayPalで支払う場合
cart.setPaymentStrategy(new PayPalPayment('[email protected]'));
cart.checkout(); // "2000 円をPayPalで支払いました(アカウント: [email protected])"

解説

  1. PaymentStrategyインターフェース

    • PaymentStrategyインターフェースは、支払い方法を表現するpayメソッドを定義しています。これにより、どの支払い方法も共通のメソッドを持つことが保証されます。
  2. 具体的な支払い方法クラス(CreditCardPaymentとPayPalPayment)

    • CreditCardPaymentPayPalPaymentは、それぞれPaymentStrategyを実装しており、異なる支払い方法の処理を提供します。
  3. ShoppingCartクラス(コンテキスト)

    • ShoppingCartクラスは、商品の追加と支払い方法の設定、そしてチェックアウトを行うクラスです。setPaymentStrategyメソッドで支払い方法を設定し、checkoutメソッドで選択された支払い方法を使って支払いを行います。
  4. 実際の使用例

    • ショッピングカートに商品を追加し、支払い方法を動的に切り替えながら支払いを行います。クレジットカードとPayPalの支払いを簡単に切り替えることができます。

利点

  • アルゴリズムの切り替えが容易: 動作を切り替える必要がある場合でも、クラスの内部を変更することなく異なるアルゴリズムを使用できます。
  • オープン/クローズド原則に準拠: 新しいストラテジーを追加する場合でも、既存のコードに影響を与えずに拡張が可能です。
  • コードの再利用性向上: アルゴリズムごとに独立したクラスを作成するため、コードの再利用性が向上します。

使用例

  • 支払いシステム: オンラインショッピングなどで、クレジットカードやPayPalなど異なる支払い方法を選択できるようにする場合。
  • ソートアルゴリズムの選択: 異なるソートアルゴリズムを動的に切り替える必要がある場合(例: クイックソートやマージソート)。
  • データ圧縮: 圧縮アルゴリズムを動的に選択する場合(例: ZIP、RAR、GZIPなど)。

まとめ

ストラテジーパターンは、動作を柔軟に切り替える必要がある場合に非常に有用なパターンです。TypeScriptのインターフェースとクラスを活用することで、各アルゴリズムを独立して実装し、必要に応じて簡単に切り替えることができます。

このパターンを理解し、適切に使うことで、特に複数の処理方法を持つアプリケーションにおいて、保守性と拡張性を高めることができます。