クラス設計:管理責任はどこにあるのか?

コラム

先日、クラス設計についてChatGPTに問題を作ってもらったところ、面白い話題になりました。
ChatGPTが出した問題は、動物園をシミュレーションするクラスを作ってくださいというものでした。

class Animal
class Lion : Animal
class Elephant : Animal
class Bear : Animal
class Zoo
class ZooKeeper
class WeatherSystem

などのクラスがあり、ZooクラスがAnimalやZooKeeperのリストを持っていたりして、それぞれに影響を与えます。
WeatherSystemクラスというのは、動物園内の天候を管理するクラスで、天気によって飼育員や動物などに色々な影響を与えます。

問題では、Animalクラスに健康状態(HealthStatus)を持たせて、WeatherSystemが状況に応じて各動物の健康状態に作用しなさいというものでした。
WeatherSystemクラスの目的と役割は、以下のように定義されています。

目的:動物園内の天候を管理し、天候が動物の行動や健康に与える影響をシミュレートします。
役割:定期的に天候を変更し、例えば晴れの日、雨の日、雪の日などのシナリオを作り、動物の行動や健康に影響を与えます。

ChatGPTでは答えも書いてくれていて、WeatherSystemクラスを以下のように実装していました。

public class WeatherSystem
{
    public string CurrentWeather { get; private set; }

    public WeatherSystem()
    {
        CurrentWeather = "Sunny"; // 初期天候は晴れ
    }

    public void ChangeWeather(string newWeather)
    {
        CurrentWeather = newWeather;
        Console.WriteLine($"The weather has changed to {CurrentWeather}.");
    }

    public void InfluenceAnimals(List<Animal> animals)
    {
        foreach (var animal in animals)
        {
            if (CurrentWeather == "Rainy" && animal is Lion)
            {
                Console.WriteLine($"{animal.Name} is hiding from the rain.");
            }
            else if (CurrentWeather == "Sunny" && animal is Bird)
            {
                Console.WriteLine($"{animal.Name} is enjoying the sunshine and flying.");
            }
            // 他の天候の影響を追加する
        }
    }
}

さて、ここで思ったのは「動物の健康状態を天候が操作すべきか?」です。
WeatherSystemクラスの目的と役割の定義を見ると、このコードは目的と役割に沿ったものになっています。
しかし、天候が動物の健康状態を管理しているのでしょうか?
それとも動物が天候の影響を受けているのでしょうか?
それとも別の何かが動物の健康状態をコントロールしているのでしょうか?

誰(何)が管理すべきで責任を持つべきでしょうか?

これはクラス設計者の価値観によって変わります。
答えはなかなか一意に定まりません。
考え方なのです。

これがクラス設計の難しいところだと思います。
そしてこれがやっかいなのは、どのアプローチでも結果は変わらない(AnimalのHealthStatusが変化することは同じ)ため、どうでもいいっちゃどうでもいいことです。
雑に設計しても実装が正しければちゃんと動くのです。
でもここでしっかり設計をしておかないと、システムが大きくなっていった場合に綻びが出始めます。
そしてその頃には設計者は既に現場にいなかったりします。

もし健康管理は動物の責任だと思えば、InfluenceAnimals()関数はAnimalクラスが持ち、WeatherSystemの情報を取得して決定を行うべきでしょう。
もし動物の健康は様々な要因で決まると思えば、別のクラス(AnimalHealthControllerなど)を作成し、色々な情報を複合的に判断し決定を行うようにしたほうが理にかなっているかもしれません。

どのような仕組みにするかの1つの指標として、現実世界の理に即しているかや、共感が得られやすい、理解されやすいかなどがあるかと思います。
本来、動物の健康は様々な要因が絡んでいると思いますが、あまりにリアルにしたせいで複雑な仕組みになってしまうと無駄が多くなってしまいますので、適度な割り切りは必要になります。

例えば、風邪をひくのは天気のせいだけではないと思いますが、山火事のように暑さと湿度のせいで燃えるのは、ほぼ天候のせいだといえます。
動物が燃えようと思って燃えるわけではないので、そういう場合はWeatherSystemが操作するのが適切かもしれません。

クラス設計が難しいのは、私たちが普段世の中の仕組みについて、因果を細かく理解して生きているわけではないので、決めてくださいと言われてもなかなか決められないところにも要因があるように思います。
まして、結果は変わらないわけですからね。
時間がなかったら「もう適当でいいや」って思っちゃいますよね、普通。

でもここをいかにスマートに設計するかがプログラムの面白いところでもあります。
上手に設計をするには、世の中の色々な仕組みを見て「ここはイケてる」とか「ここは無駄」みたいなことに興味を持つのが良いんじゃないかなと思います。

コメント

タイトルとURLをコピーしました