2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで実現するストラテジーパターン:振る舞いの切替と疎結合設計

Posted at

概要

**ストラテジーパターン(Strategy Pattern)**は、
「あるアルゴリズムや処理の振る舞いを、動的に差し替え可能にする設計手法」である。

このパターンを使うことで、if-elseswitch 文による処理分岐を排除し、
オブジェクト指向の原則に基づいた、拡張に強い柔軟な構造を構築できる。

本稿では、Pythonでの実装方法と、現場で活かせるパターン適用の実務例を紹介する。


1. なぜストラテジーが必要か?

❌ 条件分岐による処理切替

if payment_type == "credit":
    process_credit(payment)
elif payment_type == "paypal":
    process_paypal(payment)

新しい支払い手段を追加するたびに、条件分岐が膨張し保守性が低下


2. ストラテジーパターンの基本構造

✅ 共通のインタフェース

class PaymentStrategy:
    def pay(self, amount):
        raise NotImplementedError

✅ 具象戦略クラス

class CreditCardPayment(PaymentStrategy):
    def pay(self, amount):
        print(f"Paid {amount} via Credit Card")

class PayPalPayment(PaymentStrategy):
    def pay(self, amount):
        print(f"Paid {amount} via PayPal")

✅ コンテキスト(呼び出し側)

class PaymentProcessor:
    def __init__(self, strategy: PaymentStrategy):
        self.strategy = strategy

    def process(self, amount):
        self.strategy.pay(amount)

✅ 実行例

processor = PaymentProcessor(PayPalPayment())
processor.process(1000)

3. 動的切り替えの実装と利点

strategy_map = {
    "credit": CreditCardPayment(),
    "paypal": PayPalPayment(),
    # 他の戦略も追加可能
}

def get_processor(method):
    return PaymentProcessor(strategy_map[method])
  • 条件分岐を排除
  • 拡張時に既存コードを変更しない(OCPの実現)
  • 戦略のテストや切り替えが容易

4. 実務ユースケース

✅ 並列アルゴリズムの切り替え

class SortStrategy:
    def sort(self, data): ...

class QuickSort(SortStrategy):
    def sort(self, data): return sorted(data)

class BubbleSort(SortStrategy):
    def sort(self, data):
        # 実装略
        return data

✅ データ出力形式の動的切り替え

class ExportStrategy:
    def export(self, data): ...

class CSVExporter(ExportStrategy):
    def export(self, data): print("Exporting as CSV")

class JSONExporter(ExportStrategy):
    def export(self, data): print("Exporting as JSON")

5. Pythonならではの実装スタイル:関数戦略

✅ 戦略をクラスではなく関数で表現

def credit_strategy(amount):
    print(f"Credit: {amount}")

def paypal_strategy(amount):
    print(f"PayPal: {amount}")

def process_payment(strategy, amount):
    strategy(amount)

軽量かつ関数型志向な設計も可能
→ 小規模・一時的な切り替えに有効


6. よくある誤用と対策

❌ インタフェースを定義せず共通性が破綻

→ ✅ Strategy インタフェース(抽象基底クラス or プロトコル)を定義すべき


❌ コンテキスト側が戦略の中身を知ってしまう

→ ✅ コンテキストは strategy.pay() のように抽象的に操作するべき


結語

ストラテジーパターンは、「振る舞いを切り替えられる構造を、構文ではなく設計で実現する」ための手法である。

  • 分岐を排除し、拡張に強いアーキテクチャを構築
  • 戦略ごとのコードを明示的に分離し、単体テストしやすくする
  • 関数ベース・クラスベース・DIコンテナと組み合わせた多様な設計が可能

Pythonicとは、“制御の流れすらオブジェクトとして管理する”ことであり、
ストラテジーパターンはその意図を、構造として洗練する強力な手段である。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?