はじめに
プログラマーになって1年経ってプログラミング言語はハックできたのでデザインパターンを学びます。
ひとまずChatGPTに聞いてみた
Strategy Patternについて詳しく教えて
GPTの答え
もちろん、Strategy Patternについて詳しく説明します。
Strategy Patternとは
Strategy Patternは、アルゴリズムや振る舞いを定義する方法の一つです。このパターンを使用すると、アルゴリズムの家族を定義し、それぞれをカプセル化して、交換可能にします。Strategy Patternを使用すると、アルゴリズムを使用するクライアントから独立してアルゴリズムを変更できるようになります。主な要素
Strategy (ストラテジ): すべての具体的な戦略が実装するインターフェースや抽象クラス。
ConcreteStrategy (具体的なストラテジ): Strategyのインターフェースを実装するクラス。異なるアルゴリズムや振る舞いがここで定義されます。
Context (コンテキスト): Strategyを使用するクラス。コンテキストは、Strategyインターフェースを通じてConcreteStrategyを実行します。
利点
変更に柔軟: Strategy Patternを使用すると、アルゴリズムの変更や追加が容易になります。
再利用性: 同じアルゴリズムや振る舞いを持つ複数のクラス間でストラテジを再利用できます。
コードの整理: 似たような条件分岐が多数存在する場合、それをStrategy Patternで整理して、コードを簡潔にすることができます。
実装例 (Pythonを使用)
from abc import ABC, abstractmethod
# Strategy
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount: float) -> None:
pass
# ConcreteStrategy 1
class CreditCardStrategy(PaymentStrategy):
def pay(self, amount: float) -> None:
print(f"Paying {amount} using Credit Card.")
# ConcreteStrategy 2
class PayPalStrategy(PaymentStrategy):
def pay(self, amount: float) -> None:
print(f"Paying {amount} using PayPal.")
# Context
class ShoppingCart:
def __init__(self, payment_strategy: PaymentStrategy):
self._payment_strategy = payment_strategy
def checkout(self, amount: float) -> None:
self._payment_strategy.pay(amount)
# 実行
cart1 = ShoppingCart(CreditCardStrategy())
cart1.checkout(100)
cart2 = ShoppingCart(PayPalStrategy())
cart2.checkout(100)
このサンプルでは、2つの異なる支払い方法(CreditCardとPayPal)をStrategy Patternを使って実装しています。ShoppingCartクラスはContextとして機能し、具体的な支払いストラテジを受け取り、それを使用してcheckoutを行います。
Strategy Patternは、アルゴリズムや振る舞いが変更される可能性がある場面や、異なる種類のアルゴリズムを簡単に切り替える必要がある場面で非常に役立ちます。
全部説明してくれた。
図も出力していただきました。
リッチなのでGPT-4を使っています。
Strategyが実際の処理を呼び出すインターフェースの役割だがこいつのおかげで継承よりもオブジェクトの結合が緩くなって改修がしやすいらしい
中身に脳のリソース取られたくない時も実際の処理部分がカプセル化されてることで楽だね
パターンを使う時
-
アルゴリズムの変更や交換が予想される場合: もしアプリケーションの特定の部分において、使用するアルゴリズムや振る舞いを容易に変更したいと考える場面。
-
多数の条件分岐: 一つの操作に対して多くの実装方法や条件分岐が存在する場合、それぞれの分岐を独立したストラテジとして切り分けることで、コードが読みやすく、メンテナンスしやすくなります。
-
類似のクラスが多い場合: 類似の振る舞いを持つが、いくつかのアルゴリズムの部分だけが異なるクラス群が存在する場合、共通のストラテジインターフェースを使用することでコードの重複を避けることができます。
-
クライアントが知識を持たずにアルゴリズムを選択したい場合: クライアントが特定のストラテジの具体的な実装に依存せずに、動的にアルゴリズムを選択・交換できる柔軟性を持たせたいときに利用します。
-
テストのしやすさを保ちたい場合: 独立したストラテジを持っていると、それぞれのストラテジを独立してテストすることが容易になります。MockやStubを利用して、特定のストラテジをテスト時に置き換えることも簡単です。
4がStrategy Patternの1番のメリットじゃない?簡単に実装者が動的に処理変えれるのはユーザーももちろんだけど賢い人に処理部分書いてもらったらこちとら呼び出すだけでインデント揃えることに集中できるじゃん
終わり
Strategy Patternは、アルゴリズムや振る舞いの変更・追加を容易にし、システム全体の柔軟性と拡張性を向上させるデザインパターン。
最初がんばろ!あとから楽しよって話