意思決定の条件が頻繁に変わる可能性があるため、メンテナンスが容易な意思決定アルゴリズムを実装するためのエレガントな方法を見つけようとしています。
ここで例を挙げて、より具体的にしようと思います:
私がレストランの厨房で料理人のチームを管理しようとしているとしましょう。
すべてのシェフは、3種類のパイの調理方法を知っています:Appleパイ、パンプキンパイ、ラズベリーパイ、2種類のピザ:チーズピザとベーコンピザ。全員がすべての調理方法を知っています。
さて、これらのチーフに、クライアントに何が来るのかについて注文を送りたいと思います。
条件は次のとおりです。
チーフは一度に1つのパイしか調理できません。たとえば、シェフにAppleパイの調理を命じた場合、Appleパイが完成しない限り、ラズベリーパイやパンプキンパイの調理を命じることはできません。または、Appleパイのキャンセルリクエストを送信します。
さまざまなクライアント向けであるため、シェフに一度に最大5つのピザを調理するように依頼できます。
特定のシェフがすでに調理しているものに関して、特定のシェフに送信できる一連の注文を返すアルゴリズムを作成したいと思います。
私はC++で作業しています。簡単なswitch/caseステートメントを書くこともできますが、条件が変わったり、新しいパイが追加されたりすると、メンテナンスが簡単になりません。
私はちょっと立ち往生していて、条件と意思決定をカプセル化して、条件間の結合を減らし、パイ調理の条件を簡単に保守できるようにする方法がわかりません。
複雑な意思決定アルゴリズムの実装をどのように処理しますか?
データは、Chefs
、Orders
および単一のSchedule
で構成されます。 Chefs
はめったに変更されませんが、Orders
は常に作成、削除、オプションで編集されており、それに応じてSchedule
を変更する必要があることに注意してください。
新しいSchedule
のロジックは、実際にはChefs
、Orders
、oldSchedule
を含むすべてのデータに依存します。そのため、スケジューリングロジックをScheduler
クラスなどの1つの場所にまとめる必要があります。
テスト駆動開発の使用は、この問題に非常に適しています。単純なケースの単体テストを作成することから始めて、Chefs
がすでにキューにあるものをキューに入れてから、新しい注文が入ってくるか、削除または編集される、より複雑なものまで構築します。次に、Scheduler
クラスで、ルールを表現するために考えられる最も単純なロジックを記述します。必要な内部アーキテクチャまたは構造を完全に自由に使用できます。複雑すぎたり、トリッキーになったりしないでください。ロジックをよりシンプルで理解しやすくする機会を見つけたら、それを実行し、すべてのテストに合格することを確認してください。
ここで、変更を加える場合は、新しいテストケースを追加し、既存の正しくないテストケースを変更してから、すべてのテストに再度合格するまでScheduler
のロジックを変更します。このようにして、既存の仮定や論理を破ることがないことがわかります。
私はこれをいくつかの同様の問題でうまく使用しました。
これにswitchステートメントが必要なのはわかりません。これが私がこれをどのように設計するかです。タスクを割り当てる、ある種のコントローラーまたはマネージャーオブジェクトがあります。このオブジェクトは知っているでしょう
このオブジェクトに「誰かにラズベリーパイを作ってもらいます」と尋ねると、無料のオブジェクトが見つかるまでシェフをループし、ラズベリーパイを実行できるかどうかを尋ね、実行できる場合はそれを割り当てます。
一方、シェフオブジェクトでは、何を調理できるか、それぞれの能力、そして現在何を調理しているかを知る必要があります。あなたは何も料理していません、あなたはあなたが自由であるかどうか尋ねられます、あなたはそう言います、あなたはそれを追跡するために料理する何かを与えられます、そしてあなたがそれが終わる前にもう一度尋ねられたらあなたはいいえと言います。
1つのパイと5つのピザの複雑さで、「あなたは自由ですか」と「料理できますか」の質問を「Xを自由に料理できますか?」に組み合わせることができます。方法がわからないからなのか、忙しいからなのか、あなたはノーと言うでしょう。そうすれば、外出先で2つのピザを持っている人は、ピザには「はい」と言いますが、パイには「いいえ」と言います。
アサイナオブジェクトは、すべてのシェフが忙しいと言った場合にどうなるかを理解する必要もあります。シェフは彼らがしていることを終えて自由になるので、おそらく待ってもう一度尋ねてください。これは、一時停止してポーリングするか、シェフが空いたときに担当者に合図することで行うことができます。
私にとって重要なのは、シェフが何とどれくらいの時間彼らが料理できるかを知っているということです。担当者は、シェフの数を知っています。新しいパイを追加するということは、シェフクラスを更新することを意味し(パイのリストが列挙型であり、すべてのシェフが常にすべての種類のパイを調理できる場合は、おそらく再コンパイルするだけです)、コードがラズベリーパイを今すぐ作成することを決定します。通常、このような状況では、アサイナコードを変更する必要はありません。それでも、「チーズピザを「はい」または「いいえ」でできますか」と尋ねるシェフをループしています。はいの場合は、それをシェフに割り当てて戻ります。