1707135334
2024-02-05 11:22:21
RUGBY_1 チャレンジの目的は、スクラムの各ラインに異なる計算方法を適用することです。3 つのラインがそれぞれ異なる動作をします。 ただし、各ラインは同じ構造を持ち、プレーヤーで構成されています。
したがって、ここでの考え方は、これらのさまざまな計算方法を構造化することです。 デザインパターン 戦略。
この修正の議題:
デザインパターン戦略とは何ですか?
ルデザインパターン 戦略 を使用すると、アルゴリズムのファミリーを定義し、それぞれを別のクラスにカプセル化し、それらを交換可能にすることができます。 これは、コードのユーザーが実装の詳細を知る必要がなく、実行コンテキストに応じてアルゴリズムの選択を動的に変更できることを意味します。
したがって、スクラムの各ラインには独自の影響計算戦略があります。
UML のクラス構造
ここでは厳密な意味での UML 図については説明しませんが、クラスがどのように構成されているかを視覚化することができます。
この図に関する説明と、オブジェクト指向プログラミングに関する注意点をいくつか示します。
- 左側にはさまざまな戦略が表示されます。 これらはすべて同じインターフェイスを実装しています。 これにより、使用されるストラテジーに関係なく、各クラス、各ストラテジーに呼び出すことができるメソッドが確保されます。
- 右側には、課題の構造にリンクされたクラスがあり、すべてが適切に分割されています。
- スクラム:3本のラインからなるスクラム
- ライン: プレーヤーと影響力のある戦略が存在するライン
- 選手:特徴とインパクトのある選手
- これらのクラスにはそれぞれ Impact メソッドがあり、相互に呼び出して合計の影響を計算します。
PHP でのデザインパターン戦略の実装
そこでインターフェースから始めます。 インターフェイスには、実装されるメソッドの宣言のみが含まれます。
interface ImpactStrategy
{
public function calculateImpact(Player $player): int;
}
各戦略は 1 行に 1 つずつです。 各戦略は、それぞれ独自のバージョンを持つ CalculateImpact メソッドを実装する必要があります。
最初の行:
class FirstLineStrategy implements ImpactStrategy
{
public function calculateImpact(Player $player): int
{
return (int) floor($player->impact() * 1.5);
}
}
二行目:
class SecondLineStrategy implements ImpactStrategy
{
public function calculateImpact(Player $player): int
{
return $player->impact();
}
}
3行目:
class ThirdLineStrategy implements ImpactStrategy
{
public function calculateImpact(Player $player): int
{
return (int) floor($player->impact() * 0.75);
}
}
したがって、各行にはその係数が適用されます。 2行目には係数がないので、プレイヤーのインパクトを直接返します。
ここで、calculateImpact メソッドの各バージョンの内容は単純です。 しかし、もちろん、さまざまな戦略の機能的な観点からははるかに複雑で、何よりもはるかに遠いものになる可能性があります。
他のクラスでの戦略の使用
Player クラスから始めましょう。
class Player
{
public function __construct(
public readonly int $poids,
public readonly int $force
) {}
public static function createFromText(string $informations): Player
{
$values = explode(':', $informations);
return new self(
(int) $values[0],
(int) $values[1]
);
}
public function impact(): int
{
return $this->poids * $this->force;
}
}
ちょっとした説明:
- コンストラクターでプロパティのプロモーションを使用します
- 分析は、クラス自体のインスタンスを返す静的メソッドを通じて行われます。 これにより、解析をコンストラクターから適切に分離できるため、データが文字列の形式で到着するという事実とクラスの構造を結び付けることがなくなります。
- Impact メソッドは重量と力の積を返します。これは各プレイヤーに対して同じ計算です。 係数の適用は行レベルで行われます。
これが Line クラスです。このレベルでは、 パターン 戦略 :
class Line
{
/**
* @var Player[] $players
*/
private array $players = [];
private ImpactStrategy $strategy;
/**
* @param string[] $playersInformations
*/
public function __construct(array $playersInformations, ImpactStrategy $strategy)
{
foreach ($playersInformations as $playerInformations) {
$this->players[] = Player::createFromText($playerInformations);
}
$this->strategy = $strategy;
}
public function impact(): int
{
$impact = 0;
foreach ($this->players as $player) {
$impact += $this->strategy->calculateImpact($player);
}
return $impact;
}
}
ちょっとした説明:
- コンストラクターの最初のパラメーターはプレーヤー配列であり、createFromTexte メソッドを使用して情報を解析します。
- 2 番目のコンストラクター パラメーターは、インターフェイスに従って型指定されます。 これは、あらゆる ImpactStrategy を受け入れます。
- したがって、impact() メソッドでは、ライン内の各プレイヤーに応じた戦略の影響の計算を使用します。
次に、スクラム、スクラムクラス:
class Scrum
{
public function __construct(
private Line $firstLine,
private Line $secondLine,
private Line $thirdLine,
) {}
public function impact(): int
{
return $this->firstLine->impact() + $this->secondLine->impact() + $this->thirdLine->impact();
}
}
ちょっとした説明:
- 3 行をインスタンス化するためのコンストラクター内のプロパティのプロモーションをさらに強化しました。
- Impact() メソッドは、ここで 3 行の影響の合計を返します。
- ラインのテーブルを作成することもできましたが、スクラム (この文脈では) は常にこのように編成された 3 つのラインを持ちます。 したがって、必要ありませんでした。
そして最後に、メインプログラム:
// $line1, $line2 et $line3 sont les données du challenge
$scrum = new Scrum(
new Line($line1, new FirstLineStrategy),
new Line($line2, new SecondLineStrategy),
new Line($line3, new ThirdLineStrategy),
);
// Impact total
$scrum->impact();
完全なコードは次の場所から入手できます。 ギットハブ。
結論
なぜ「new FirstLineStrategy」を引数としてコンストラクターに渡すのか、そしてなぜ次のようにしないのか疑問に思うかもしれません。
new Line($line1, 'FirstLineStrategy');
// Pour faire ensuite dans le constructeur de Line
$strategy = new $strategyName;
インスタンスをパラメータとして直接渡すことにより、次の 2 つの利点が得られます。
- タイプセーフティ : Line コンストラクターは、2 番目のパラメーターとして「ImpactStrategy」タイプを想定しています。 それ以外のものを渡すと、すぐにエラーが発生します。 クラス名を渡すと、あまり制御せずに「string」と入力することになります。
- デカップリング : この原則は、クラス間の依存関係を減らすことで構成されています。 その考え方は、システムの「コンポーネント」の相互依存性を低くし、システム内のある場所を変更しても他の場所での変更が強制されないようにすることです。 これにより、全体がよりモジュール化され、理解、保守、テスト、拡張などが容易になります。 それは本当に尊重し、実践することです。
結論として、 デザインパターン 戦略 を使用すると、同様の動作を持つアルゴリズムのファミリーを作成し、それらをさまざまなクラスに正しく編成し、それらを必要とする他のクラスで使用できます。 を使用することが賢明と思われるいくつかの実際的なケース デザインパターン 戦略 (もちろん、コードのコンテキストとニーズに応じて適応されます):
- 支払いシステム: さまざまな支払い方法を動的に選択します
- 並べ替えアルゴリズム: データ形式または量に基づいて並べ替えタイプを選択します
- 割引管理: 顧客または注文プロファイルに応じて、異なる割引メカニズムを適用します。
- フォームからのデータの検証: 入力されたデータの種類 (名、電子メール、日付、銀行情報など) に応じて異なるコントロールを適用します。
- コンテンツの推奨事項: ユーザーのステータスと履歴に応じて、さまざまな方法とアルゴリズムを使用して提供するコンテンツを取得します。
- 等。
でトレーニングするには デザインパターン PHP での戦略、たとえばそれをチャレンジに適用できます エクスプレスセンター、注文内のアイテムの種類ごとに戦略を定義します。
ボーナス: Pest PHP を使用した単体テスト
コードは完全にテストされています 害虫PHP。 テストは次の場所で利用できます ギットハブ また。
#POO #PHP #パターン戦略の設計