我的域模型中有几个不同的实体(比如说动物物种),每个实体都有一些属性。实体是只读的(它们在应用程序生命周期内不会更改状态)并且它们具有相同的行为(仅在属性值上有所不同)。
如何在代码中实现这些实体?
不成功的尝试:
枚举
我尝试了这样的枚举:
enum Animals {
Frog,
Duck,
Otter,
Fish
}
其他代码将打开枚举。然而,这会导致难看的切换代码,分散逻辑和组合框的问题。没有漂亮的方法可以列出所有可能的动物。序列化虽然效果很好。
子类
我还考虑了每种动物类型在哪里是公共基础抽象类的子类。但是,所有 Animals的 Swim() 的实现都是相同的,所以它没有什么意义,而且可序列化现在是一个大问题。因为我们代表一种动物类型(物种,如果你愿意的话),每个应用程序应该有一个子类的实例,当我们使用序列化时,维护起来既困难又奇怪。
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();
}
那太好了:你可以像 enums ( AnimalType = Animal.Otter
) 一样使用它,你可以轻松地添加所有已定义动物的静态列表,你有一个明智的地方来实现Swim()
。可以通过保护属性设置器来实现不变性。但是有一个主要问题:它破坏了可序列化性。一个序列化的 Animal 必须保存它的所有属性,并且在反序列化时它会创建一个 Animal 的新实例,这是我想避免的。
有没有一种简单的方法可以使第三次尝试成功?对于实施这样的模型还有什么建议吗?