計算機科学のブログ

Interfaces, casting, and is: Making classes keep their promises - refactoring

Head First C Sharp: A Learner’s Guide to Real-World Programming with C Sharp and .NET (Andrew Stellman(著)、Jennifer Greene(著)、O’Reilly Media)の Chapter 7(Interfaces, casting, and is: Making classes keep their promises)、p.371(Exercise)の解答を求めてみる。

コード

IWorker.cs

using System;

namespace ConsoleApp3;

public interface IWorker
{
    public string Job { get; }
    void WorkTheNextShift();
}

Bee.cs

using System;

namespace ConsoleApp3;

public abstract class Bee : IWorker
{
    public string Job { get; private set; }
    public virtual float CosntPerShift { get; }
    public Bee(string job)
    {
        Job = job;
    }
    public void WorkTheNextShift()
    {
        if (HoneyVault.ConsumeHoney(CosntPerShift))
        {
            DoJob();
        }
    }
    protected virtual void DoJob() { }
}

Queen.cs

using System;

namespace ConsoleApp3;

public class Queen : Bee
{
    private const float EGGS_PER_SHIFT = 0.45f;
    private const float HONEY_PER_UNASSIGNED_WORKER = 0.5f;
    public string StatusReport { get; private set; } = "";
    private IWorker[] workers = new Bee[0];
    private float eggs = 0;
    private float unassignedWorkers = 3;
    public override float CosntPerShift => 2.15f;
    protected override void DoJob()
    {
        eggs += EGGS_PER_SHIFT;
        foreach (IWorker worker in workers)
        {
            worker.WorkTheNextShift();
        }
        HoneyVault.ConsumeHoney(HONEY_PER_UNASSIGNED_WORKER * workers.Length);
        UpdateStatusReport();
    }
    public void AssignBee(string job)
    {
        switch (job)
        {
            case "Honey Manufacturer":
                AddWorker(new HoneyManufacturer());
                break;
            case "Nectar Collector":
                AddWorker(new NectarCollector());
                break;
            case "Egg Care":
                AddWorker(new EggCare(this));
                break;
        }
        UpdateStatusReport();
    }

    private void AddWorker(IWorker worker)
    {
        if (unassignedWorkers >= 1)
        {
            unassignedWorkers--;
            Array.Resize(ref workers, workers.Length + 1);
            workers[workers.Length - 1] = worker;
        }
    }
    public void CareForEggs(float eggsToConvert)
    {
        if (eggs >= eggsToConvert)
        {
            eggs -= eggsToConvert;
            unassignedWorkers += eggs;
        }
    }
    private void UpdateStatusReport()
    {
        int nectarCollector = 0;
        int honeyManufacturer = 0;
        int eggCare = 0;
        foreach (IWorker worker in workers)
        {
            switch (worker.Job)
            {
                case "Nectar Collector":
                    nectarCollector++;
                    break;
                case "Honey Manufacturer":
                    honeyManufacturer++;
                    break;
                case "Egg Care":
                    eggCare++;
                    break;
            }
        }
        StatusReport = "Vault report:\n" +
        HoneyVault.StatusReport + "\n" +
        $"Egg count: {eggs}\n" +
        $"Unassigned workers: {unassignedWorkers}\n" +
        $"{nectarCollector} Nectar Collector bee";
        if (nectarCollector > 1) StatusReport += "s";
        StatusReport += $"\n{honeyManufacturer} Honey Manufacturer bee";
        if (honeyManufacturer > 1) StatusReport += "s";
        StatusReport += $"\n{eggCare} Egg Care bee";
        if (eggCare > 1) StatusReport += "s";
        StatusReport += $"\nTOTAL WORKERS: {workers.Length}";
    }


    public Queen() : base("Queen")
    {
        string[] jobs = ["Heny manufacturer", "Nectar Collectar", "Egg Care"];
        foreach (string job in jobs)
        {
            AssignBee(job);
        }
    }

}