割り当てロジックを差し替え可能にする
## ストーリー
TicketCraftでは、新しく作成されたチケットを誰に割り当てるかを決定するロジックが`AssignmentManager`クラスに固められています。開発者はラウンドロビン方式で割り当てていましたが、ある日チームから「負荷の少ない人に優先的に回したい」という要望が上がりました。
既存の`assignTicket`メソッドの中に割り当てルールがハードコーディングされているため、ルールを追加するたびにメソッド全体を書き換えたり、条件分岐を増やしたりする必要があります。
記事「[Strategyパターン|チケット割り当てロジックを実行時に切り替える](https://nanade.net/blog/pattern-strategy/)」で学んだ「アルゴリズムを実行時に差し替え可能にする」考え方を使って、`AssignmentManager`を書き換えてください。
## 課題
雛形の`AssignmentManager`クラスを、次の条件をすべて満たすように書き換えてください。
1. `User assign(User... users)`を1つだけ持つ`AssignmentStrategy`インターフェースを定義する
2. `RoundRobinAssignment`クラスを`AssignmentStrategy`として実装する(呼び出すたびに次のユーザーへ順番に割り当てる)
3. `LoadBalancedAssignment`クラスを`AssignmentStrategy`として実装する(保留件数`getPendingWork()`が最小のユーザーに割り当てる)
4. `AssignmentManager`はコンストラクタ`AssignmentManager(AssignmentStrategy strategy)`で初期戦略を受け取り、`setStrategy(AssignmentStrategy strategy)`で実行時に戦略を差し替えられるようにする
5. `assignTicket(Ticket ticket, User... users)`は、保持している戦略に処理を委譲する(`strategy.assign(users)`の結果をチケットに割り当てる)
`Ticket`・`User`クラスは変更不要です(雛形のまま使えます)。
`users`には必ず1人以上が渡される前提とします(0人のケースは考慮不要です)。保留件数が同点の場合は、`users`の中で最初に見つかった1人を選ぶ実装にしてください(`for`文で先頭から見ていき、より小さい値が見つかったときだけ更新する素直な実装であれば自然にそうなります)。
## 手順
1. **Step 1**: `AssignmentStrategy`インターフェースを定義する(`User assign(User... users);`の1メソッドのみ)
2. **Step 2**: `RoundRobinAssignment`を実装する。呼び出し回数を数える`index`フィールドを持ち、呼ばれるたびに`users[index % users.length]`を返して`index`を1増やす
3. **Step 3**: `LoadBalancedAssignment`を実装する。渡された`users`の中で`getPendingWork()`が最小の1人を返す
4. **Step 4**: `AssignmentManager`にフィールド`strategy`を追加し、コンストラクタと`setStrategy`で設定できるようにする
5. **Step 5**: `assignTicket`を、`strategy.assign(users)`で選ばれたユーザーを`ticket.assign(...)`する実装に書き換える(ハードコードされたラウンドロビンのロジックは削除する)
## 期待される実行結果の例
```java
User alice = new User("Alice", 0);
User bob = new User("Bob", 1);
User charlie = new User("Charlie", 2);
AssignmentManager manager = new AssignmentManager(new RoundRobinAssignment());
Ticket t1 = new Ticket(1, "ログインエラー");
manager.assignTicket(t1, alice, bob, charlie);
t1.getAssignee().getName(); // => "Alice"(1回目)
manager.setStrategy(new LoadBalancedAssignment());
Ticket t2 = new Ticket(2, "パスワードリセット");
manager.assignTicket(t2, alice, bob, charlie);
t2.getAssignee().getName(); // => "Bob"(Aliceは1回目の割り当てで保留件数1、Bob/Charlieは0。0の中で最初に見つかったBobが選ばれる)
```
提出すると、この記事と同じ観点の隠しテスト(合計6件)で自動採点されます。全件通過で合格です。