Pythonでデザインパターンを学ぶ(Strategy)

Python

こんにちは、ユウです。

現在、デザインパターンについて勉強しています。本記事ではStrategyパターンについて紹介したいと思います。

ユウ
ユウ

以下の2つの書籍で勉強していますが、わかりやすくておすすめです!

Strategyというのは「戦略」という意味で、プログラミングの文脈では「アルゴリズム」を意味すると考えられます。

Strategyパターンは、戦略(アルゴリズム)の切り替えを容易にするためのパターンです。

Strategyパターンを使うことでプログラムの実行時にアルゴリズムを切り替えることもできます。

Strategyパターンには以下の3つの登場人物がいます:

Strategy(戦略)

戦略を利用するためのインターフェースを定める役です。

Concrete Strategy(具体的戦略)

Strategy役のインターフェースを実際に実装する役です。

Context(文脈)

Strategy役を利用する役です。

Context役は、Concrete Strategy役のインスタンスを状態として保持し、それを必要に応じて使用します。言い換えると、Context役は、処理の一部(アルゴリズム)をConcrete Strategy役に委譲します。

以下、Strategyパターンのクラス図です。

以下、Strategyパターンを使ったサンプルコードとして、お金の支払い方法(アルゴリズム)を切り替える例を考えます。

支払い方法としては、1. 現金を使った支払い、2. クレジットカードを使った支払い、を考え、これらを切り替えられるようにします。

Strategy

まず、インターフェースであるStrategy役として、以下のPaymentStrategyを実装します。

PaymentStrategyは、お金を支払うメソッド(pay)を抽象メソッドとして備えます。

# payment_strategy.py

from abc import ABC, abstractmethod


class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

Concrete Strategy

上で定義したインターフェースの実装として、2つのConcrete Strategy役のクラスを実装します。

(1) 現金での支払いに対応するConcrete Strategy

# cash_payment.py

from payment_strategy import PaymentStrategy


class CashPayment(PaymentStrategy):
    def pay(self, amount):
        print(f"現金で{amount}円支払います")

(2) クレジットカードでの支払いに対応するConcrete Strategy

# credit_card_payment.py

from payment_strategy import PaymentStrategy


class CreditCardPayment(PaymentStrategy):
    def __init__(self, card_number):
        self.card_number = card_number

    def pay(self, amount):
        print(f"クレジットカード{self.card_number}{amount}円支払います")

Context

Concrete Strategyを利用するContext役のクラスとして、以下のPersonクラスを実装します。

Personクラスは、初期化時にConcrete Strategyを受け取ります。

また、Personクラスはお金を支払うためのメソッド(pay)を持ちますが、その処理はConcrete Strategyのpayメソッドを呼ぶだけです。つまり、Personクラスのpayメソッドは、処理をConcrete Strategyに委譲しています。

また、Personクラスは、支払い方法を切り替えるためのメソッド(set_payment_strategy)を持ちます。

# person.py

from payment_strategy import PaymentStrategy


class Person:
    # 初期化時にConcrete Strategyのインスタンスを受け取る
    def __init__(self, payment_strategy: PaymentStrategy):
        self.payment_strategy = payment_strategy

    # インターフェースを用いてメソッドを実装する
    def pay(self, amount):
        self.payment_strategy.pay(amount)

    # Concrete Strategyを切り替えるメソッド
    def set_payment_strategy(self, payment_strategy: PaymentStrategy):
        self.payment_strategy = payment_strategy

以上で定義した各クラスを用いて、支払い方法(アルゴリズム)を切り替えるコードは以下となります。

# main.py

from cash_payment import CashPayment
from credit_card_payment import CreditCardPayment
from person import Person


def main():
    # 現金で支払う場合
    person = Person(CashPayment())
    person.pay(100)

    # クレジットカードで支払う場合
    credit_card_payment = CreditCardPayment("1234-5678-9012-3456")
    person = Person(credit_card_payment)
    person.pay(200)

    # クレジットカード→現金に支払い方法を変更する
    person.set_payment_strategy(CashPayment())
    person.pay(300)


if __name__ == "__main__":
    main()

上記の実行結果は以下となります。

現金で100円支払います
クレジットカード1234-5678-9012-3456で200円支払います
現金で300円支払います
ユウ
ユウ

たしかに、支払い方法(アルゴリズム)を切り替えられていますね。

本記事ではStrategyパターンを紹介しました。

引き続きデザインパターンの勉強を進めたいと思います。

プロフィール
この記事を書いた人

30代半ばで未経験でプログラマーに転職し、日々奮闘中です
プログラミング、AI、NLP、キャリア関連などで少しでも役に立てる情報を発信していきます

ユウをフォローする
Pythonデザインパターン
ユウをフォローする

コメント

タイトルとURLをコピーしました