Strategyパターン
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 93/110。
Strategyパターンを使用すると、一連のアルゴリズムを定義し、それぞれを独自のクラスにカプセル化して、実行時にそれらを入れ替え可能にすることができます。クラスに振る舞いをハードコーディングする代わりに、インターフェースを介して振る舞いを注入することで、それを利用するクラスを変更することなく、戦略(ストラテジー)を切り替えることができます。
さまざまな支払い方法をサポートしたい決済システムを考えてみましょう。各方法を処理するために条件分岐を使用するのではなく、ストラテジーインターフェースを定義し、具体的な実装を作成します:
abstract class PaymentStrategy {
void pay(double amount);
}
class CreditCardPayment implements PaymentStrategy {
@override
void pay(double amount) => print('Paid \$amount with Credit Card');
}
class PayPalPayment implements PaymentStrategy {
@override
void pay(double amount) => print('Paid \$amount with PayPal');
}
class ShoppingCart {
PaymentStrategy _paymentStrategy;
ShoppingCart(this._paymentStrategy);
void setPaymentStrategy(PaymentStrategy strategy) {
_paymentStrategy = strategy;
}
void checkout(double total) {
_paymentStrategy.pay(total);
}
}
void main() {
var cart = ShoppingCart(CreditCardPayment());
cart.checkout(99.99); // クレジットカードで$99.99を支払いました
cart.setPaymentStrategy(PayPalPayment());
cart.checkout(49.99); // PayPalで$49.99を支払いました
}ShoppingCart は、支払いがどのように機能するかを知る必要も関与する必要もありません。現在設定されているストラテジーに委譲するだけです。カートのコードに手を加えることなく、新しいストラテジークラスを作成することで、新しい支払い方法を追加できます。このパターンは、アクションを実行する方法が複数あり、それらを動的に選択または切り替えたい場合に最適です。
チャレンジ
簡単Strategy パターンを使用して、テキストフォーマットシステムを構築しましょう!コアとなるテキストプロセッサを変更することなく、ユーザーが動的にフォーマットを切り替えられるように、テキストにさまざまなフォーマット戦略を適用できるシステムを作成します。
コードを2つのファイルに整理します:
formatting_strategies.dart: ここに戦略システムを作成します。String format(String text)メソッドを持つ抽象クラスFormattingStrategyを定義します。次に、3つの具体的な戦略を実装します:UppercaseStrategy- テキストをすべて大文字に変換しますLowercaseStrategy- テキストをすべて小文字に変換しますTitleCaseStrategy- 各単語の最初の文字を大文字にします(スペースで分割し、各単語の最初の文字を大文字に、残りを小文字にします)
FormattingStrategyを保持するTextProcessorクラスも作成します。これには、初期戦略を受け取るコンストラクタ、実行時に戦略を変更するためのsetStrategy()メソッド、および現在の戦略を適用してフォーマットされた結果を返すprocess(String text)メソッドが必要です。main.dart: フォーマット戦略をインポートし、Strategy パターンによって動作を動的に切り替える方法を示します。UppercaseStrategyで始まるTextProcessorを作成します。テキストhello worldを処理して結果をプリントします。次にLowercaseStrategyに切り替え、HELLO WORLDを処理してプリントします。最後にTitleCaseStrategyに切り替え、the quick brown foxを処理して結果をプリントします。
これは Strategy パターンの強力さを示しています。TextProcessor はフォーマットがどのように機能するかという詳細を知る必要はありません。単に現在設定されている戦略に委譲するだけで、プロセッサを修正することなく新しいフォーマットオプションを簡単に追加できます!
期待される出力:
HELLO WORLD
hello world
The Quick Brown Foxチートシート
Strategyパターンは、一連のアルゴリズムを定義し、それぞれを独自のクラスにカプセル化して、実行時にそれらを交換可能にします。振る舞いをハードコーディングする代わりに、インターフェースを通じて注入します。
ストラテジーインターフェースを定義します:
abstract class PaymentStrategy {
void pay(double amount);
}具体的なストラテジーの実装を作成します:
class CreditCardPayment implements PaymentStrategy {
@override
void pay(double amount) => print('Paid \$amount with Credit Card');
}
class PayPalPayment implements PaymentStrategy {
@override
void pay(double amount) => print('Paid \$amount with PayPal');
}ストラテジーを使用するコンテキストクラスを作成します:
class ShoppingCart {
PaymentStrategy _paymentStrategy;
ShoppingCart(this._paymentStrategy);
void setPaymentStrategy(PaymentStrategy strategy) {
_paymentStrategy = strategy;
}
void checkout(double total) {
_paymentStrategy.pay(total);
}
}ストラテジーを注入して切り替えることで、パターンを使用します:
var cart = ShoppingCart(CreditCardPayment());
cart.checkout(99.99); // クレジットカードで$99.99支払われました
cart.setPaymentStrategy(PayPalPayment());
cart.checkout(49.99); // PayPalで$49.99支払われましたコンテキストクラスは、実装の詳細を知ることなく、振る舞いをストラテジーに委譲します。既存のコードを修正することなく、新しいクラスを作成することで新しいストラテジーを追加できます。
自分で試してみよう
import 'formatting_strategies.dart';
void main() {
// TODO: UppercaseStrategyを使用してTextProcessorを作成する
// TODO: テキスト 'hello world' を処理して結果を表示する
// TODO: LowercaseStrategyに切り替える
// TODO: 'HELLO WORLD' を処理して結果を表示する
// TODO: TitleCaseStrategyに切り替える
// TODO: 'the quick brown fox' を処理して結果を表示する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ