域模型中的继承与枚举属性
-
27-09-2019 - |
题
我在工作中进行了一次关于“领域模型中的继承使开发人员的生活变得复杂”的讨论。我是一名面向对象的程序员,所以我开始寻找论据,证明在域模型中拥有继承实际上可以减轻开发人员的生活,而不是到处进行切换。
我想看到的是这样的:
class Animal {
}
class Cat : Animal {
}
class Dog : Animal {
}
另一位同事的说法是:
public enum AnimalType {
Unknown,
Cat,
Dog
}
public class Animal {
public AnimalType Type { get; set; }
}
我如何说服他(链接是 欢迎 )对于这种情况,类层次结构会比具有枚举属性更好吗?
谢谢!
解决方案
下面是如何我原因它:
只有使用继承如果角色/类型永远不会改变。 例如
使用继承的东西像:
消防员< - 雇员< - 人是错误的
只要弗雷迪消防员改变工作或变得失业了,你杀了他,并重新创建新的类型的新对象与所有连接到它的老关系。
因此,幼稚解决上述问题就会得到JOBTITLE枚举属性的人类。 这可够在某些情况下,例如如果你不需要与角色/类型关联非常复杂的行为。
更正确的方法是给予人类角色的列表。 每个角色表示e.g用的时间跨度的工作。
e.g。
freddy.Roles.Add(new Employement( employmentDate, jobTitle ));
或者如果这是矫枉过正:
freddy.CurrentEmployment = new Employement( employmentDate, jobTitle );
此方式,可以弗雷迪W / O型,我们不必首先杀他成为显影剂。
不过,我所有的随笔,如果你要使用一个或枚举类型层次的JOBTITLE还没有回答。
在纯在二OO MEM我会说,这是更正确的在这里使用继承的jobtitles。
但是,如果你正在做的,如果映射器尝试每个子类型映射到一个新的表则可能是在幕后有点过于复杂的数据模型最终O / R映射。 所以在这种情况下,我经常去的枚举的方法,如果没有与类型相关联没有真正的/复杂的行为。 我可以用活“如果类型== JobTitles.Fireman ...”,如果使用被限制,并且它使事情easer或较不复杂的。
e.g。实体框架4的设计师为.NET只能映射每个子类型的新表。你可能会得到一个丑陋的模型或很多的,当你查询数据库W / O任何实际的好处加入。
不过我使用的继承如果类型/角色是静态的。 例如产品。
你可能有CD < - 产品和图书< - 产品。 继承胜这里,因为在这种情况下,你极有可能与类型相关联的不同状态。 CD可能有多个轨道物业的同时,一本书可能有页面属性的数量。
因此,在短期,这取决于; - )
此外,在这一天结束时,你将最有可能有很多switch语句无论哪种方式的结束。 比方说,你要编辑“产品”,即使您使用继承,你将可能有这样的代码:
如果(产品是书) Response.Redicted( “〜/ EditBook.aspx ID?” + product.id);
由于在实体类编码编辑书网址是难看,因为它会迫使你的业务entites的了解你的网站结构等。
其他提示
枚举在以下情况下很有用:
- 这组值是固定的,从不或很少改变。
- 您希望能够表示值的联合(即组合标志)。
- 您不需要将其他状态附加到每个值。(Java 没有这个限制。)
如果您可以用数字解决问题,那么枚举可能很合适并且类型更安全。如果您需要比上述更多的灵活性,那么枚举可能是 不是 正确的答案。使用多态类,您可以:
静态地确保处理所有特定于类型的行为。例如,如果您需要所有动物都能够
Bark()
, , 制作Animal
带有摘要的类Bark()
方法将使编译器检查每个子类是否实现它。如果您使用枚举和大switch
, ,它不能确保您已经处理了每个案例。您可以添加新案例(示例中的动物类型)。这可以跨源文件甚至跨包边界来完成。对于枚举,一旦声明它,它就会被冻结。开放式扩展是 OOP 的主要优势之一。
值得注意的是,你同事的例子并不与你的例子直接相反。如果他希望动物的类型成为公开的属性(这对某些事情很有用),您仍然可以在不使用枚举的情况下做到这一点,使用 类型对象模式:
public abstract class AnimalType {
public static AnimalType Unknown { get; private set; }
public static AnimalType Cat { get; private set; }
public static AnimalType Dog { get; private set; }
static AnimalType() {
Unknown = new AnimalType("Unknown");
Cat = new AnimalType("Cat");
Dog = new AnimalType("Dog");
}
}
public class Animal {
public AnimalType Type { get; set; }
}
这为您提供了枚举的便利:你可以做 AnimalType.Cat
你可以得到动物的类型。但它也为您提供了课程的灵活性:您可以添加字段 AnimalType
存储每种类型的附加数据,添加虚拟方法等。更重要的是,您可以通过创建新的实例来定义新的动物类型 AnimalType
.
我也希望你重新考虑:在贫血域模型(每上述评论),猫不的的行为的不同于狗,所以没有多态。动物的类型真的是这么一个属性。很难看到继承买你。
有一个枚举就像是举办聚会,所有这些Open/Closed Principle is for suckers
人。
这真的邀请你检查是否动物是某种类型的,然后应用定制逻辑为每个类型。这可以使可怕的代码,这使得它真的很难继续建立您的系统上。
最重要的OOPS手段建模现实。继承给你机会说猫是动物。动物不应该知道如果一只猫,现在喊它,然后决定它是假设喵而不是树皮,封装被打败了那里。更少的代码,现在你不必做。如果像你说的东西。
这两种解决方案是正确的。 你应该看看哪种技术更好地应用到你的问题。
如果你的程序使用几个不同的对象,并没有增加新的类,它能够更好地留在枚举。
但是,如果你的程序使用了很多不同的对象(类不同),并且可以添加新的类,在未来,更好地尝试继承方式。