【Laravel】Strategyパターンを適用する
環境
– Laravel 9.38.0
– PHP 8.1.12
Laravel Sailで環境構築しています。
https://readouble.com/laravel/9.x/ja/sail.html
参考
Strategyパターンとは
ひとことで言えば、状況に応じてアルゴリズムを簡単に切り替えることを可能にするデザインパターンです。
きちんとした定義は下記をご覧ください。
Strategy (ストラテジー、 戦略) は、 振る舞いに関するデザインパターンの一つで、 アルゴリズムのファミリーを定義し、 それぞれのアルゴリズムを別個のクラスとし、 それらのオブジェクトを交換可能にします。
[引用] https://refactoring.guru/ja/design-patterns/strategy
普通にプログラミングしていると、メソッドの中に溶け込んだ形でアルゴリズムを実装してしまうことがよくあります。if 文などで分岐させることでアルゴリズムを変更するような方法です。Strategy パターンでは、戦略の部分を意識して別クラスとして作成するようにしています。戦略x部分を別クラスとして作成しておき、戦略を変更したい場合には、利用する戦略クラスを変更するという方法で対応します。Strategy パターンを利用することで、メソッドの中に溶け込んだ形のアルゴリズムより柔軟でメンテナンスしやすい設計となります。
[引用] https://www.techscore.com/tech/DesignPattern/Strategy
Strategy
アルゴリズムを利用するためのインターフェースです。
Concrete Strategies
Strategyインターフェースを実際に実装する具象クラス群で、それぞれのアルゴリズムごとにクラスを作成し、実装します。
Context
Concrete Strategies(具象クラス)のインスタンスを持っていて、それを利用します。(呼び出しているのはStrategyインターフェース)
今回の実装について
– 電子決済を想定
– 決済方法はApple Pay、Google Pay、クレジットカードの3つ
– コマンドは $ pay {paymentMethod}
– 入力された値に応じて決済方法と利用上限を出力する
Strategyパターンを利用しない場合
では、まずStrategyパターンを使用せずに実装してみます。
class PaymentStrategyCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'pay {paymentMethod}';
/**
* The console command description.
*
* @var string
*/
protected $description = '使用される決済方法と利用上限を表示します。';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$argument = $this->argument('paymentMethod');
$this->info(Self::getPaymentMethod($argument));
$this->info('利用上限:' . Self::getUsageLimit($argument));
return Command::SUCCESS;
}
private static function getPaymentMethod(string $commandArgument) : string
{
$paymentMethod = match($commandArgument) {
'credit' => 'クレジットカード',
'apple' => 'Apple Pay',
'google' => 'Google Pay',
default => throw new \InvalidArgumentException('credit, apple, googleのいずれかを入力してください。'),
};
return $paymentMethod;
}
private static function getUsageLimit(string $commandArgument) : string
{
$usageLimit = match ($commandArgument) {
'credit' => '¥1,000,000',
'apple' => '¥100,000',
'google' => '¥50,000',
default => throw new \InvalidArgumentException('credit, apple, googleのいずれかを入力してください。'),
};
return $usageLimit;
}
}
Strategyパターンを利用する場合
では、Strategyパターンを利用して実装していきます。
①インターフェースを作成
②具象クラスを作成
クレジットカード、ApplePay、GooglePayそれぞれの種別ごとにクラスを作成します。
これらは先ほどのPaymentMethodの具象クラスになります。
③具象クラスを利用するためのコンテキストを作成
コマンドで入力される値をコンストラクタの引数とし、その値によって対応するインスタンスを生成します。
strategy = match ($paymentMethod) {
'credit' => new CreditCardStrategy(),
'apple' => new ApplePayStrategy(),
'google' => new GooglePayStrategy(),
default => throw new \InvalidArgumentException('credit, apple, googleのいずれかを入力してください。'),
};
}
public function getPaymentMethod()
{
return $this->strategy->getPaymentMethod();
}
public function getUsageLimit()
{
return $this->strategy->getUsageLimit();
}
}
④コマンドを作成
argument('paymentMethod'));
$this->info($strategyContext->getPaymentMethod());
$this->info('利用上限:' . $strategyContext->getUsageLimit());
return Command::SUCCESS;
}
}
決済方法を追加したい場合には、PaymentMethodインターフェスを実装するクラスを追加すれば済むようになりました。
このように、Strategyパターンを利用することで決済方法の追加が容易になり、メンテナンス性を向上させることができます。
さいごに
簡易的ではありますが、今回はデザインパターンの一つであるStrategyパターンについて書かせていただきました。
少しでもお役に立てれば幸いです。
種別ごとに異なるアルゴリズムを実装する必要がある場面は頻出だと思いますので、活用してメンテナンス性高く実装していきたいです。
最後までお読みいただきありがとうございました。
関連記事
- 2023-02-13
- テクノロジー