ドメインモデルにはいくつかの異なるエンティティ(たとえば、動物種)があり、それぞれにいくつかのプロパティがあります。エンティティは読み取り専用であり(アプリケーションの存続期間中は状態が変更されません)、動作は同じです(プロパティの値のみが異なります)。
そのようなエンティティをコードで実装する方法は?
失敗した試行:
列挙型
私はこのような列挙型を試しました:
enum Animals {
Frog,
Duck,
Otter,
Fish
}
そして、他のコードは列挙型をオンにします。ただし、これにより、コードの切り替えが醜くなり、ロジックが分散し、コンボボックスに問題が発生します。すべての可能な動物をリストするためのきれいな方法はありません。ただし、シリアル化はうまく機能します。
サブクラス
また、各動物タイプが共通ベース抽象クラスのサブクラスである場所についても考えました。ただし、 Swim()の実装はすべての動物で同じであるため、ほとんど意味がなく、直列化可能性が大きな問題になっています。動物の種類(必要に応じて種)を表すため、アプリケーションごとにサブクラスのインスタンスが1つあるはずです。これは、シリアル化を使用するときに維持するのが難しく、奇妙です。
public abstract class AnimalBase {
string Name { get; set; } // user-readable
double Weight { get; set; }
Habitat Habitat { get; set; }
public void Swim(); { /* swim implementation; the same for all animals but depends uses the value of Weight */ }
}
public class Otter: AnimalBase{
public Otter() {
Name = "Otter";
Weight = 10;
Habitat = "North America";
}
}
// ... and so on
ただひどい。
静的フィールド
このブログ投稿は、各オプションが次のように型内で静的に定義されたフィールドであるソリューションのアイデアを私に与えました。
public class Animal {
public static readonly Animal Otter =
new Animal
{ Name="Otter", Weight = 10, Habitat = "North America"}
// the rest of the animals...
public string Name { get; set; } // user-readable
public double Weight { get; set; }
public Habitat Habitat { get; set; }
public void Swim();
}
それは素晴らしいことです:列挙型(AnimalType = Animal.Otter
)のように使用でき、定義されたすべての動物の静的リストを簡単に追加でき、実装するための賢明な場所がありますSwim()
。プロパティセッターを保護することで、不変性を実現できます。ただし、大きな問題があります。それは直列化可能性を壊します。シリアル化されたAnimalは、そのすべてのプロパティを保存する必要があり、逆シリアル化すると、Animalの新しいインスタンスが作成されます。これは、避けたいものです。
3回目の試行を機能させる簡単な方法はありますか?そのようなモデルを実装するためのその他の提案はありますか?