领域对象设计

3

在设计领域模型时,应该坚持使用表示问题领域的实体和概念,域模型不应包含审计信息。

因此,如果我正在设计一只猫,它可能看起来像这样:

public Cat {
    private Color furColor;
    private Color eyeColor;
    private boolean isDeclawed;
    etc...
} 

我不应该有像“updateDate”和“createTime”这样的属性,对吗?

现在,如果一个网络应用程序要在屏幕上显示一张猫的表格,你可能会有以下内容:

名字     眼睛颜色   有爪子吗?  最后更新时间
------  ---------  ------     ------------
Fluffy  绿色       否         2012年10月31日
等等...

那么,如果您不在域模型中保留最后更新时间,如何(正确地)将数据传递到页面上呢?

显然,我可以拥有一个设计不良的域模型,但我想做得更好。

我曾考虑过创建一个接受泛型的对象,这样我就可以保持我的域模型的清晰。

public PersistableObject<T,K> {

    private T domainObject;
    private Date updateDate;
    private User updateUser;

    getters, setters, etc...
}

然而,我担心在这方面会遇到一些问题。

我已经做过很多"领域模型"和"更新日期"等方面的搜索,但我觉得我错过了正确的术语。

有人能指点我一下吗?


深入挖掘,为什么你需要审计跟踪?为什么你需要显示“最后更新”列? - Yves Reynhout
2个回答

2
在您的情况下,我不确定是否同意第一句话。如果您的域名的通用使用包括需要呈现这些日期,则它们可能(并且很可能)是您正常域对象的一部分。
如果您想清理域对象,您可以简单地创建一个接口来保存那些常见的字段。
public interface ITrackedObject
{
    DateTime LastUpdated { get; set; }
    //etc....
}

public class Cat : ITrackedObject
{
    public DateTime LastUpdated { get; set; }
    //....
}

你的所有领域对象都不需要扩展 TrackedObject,只有被跟踪的对象需要。为了使其正常工作,LastUpdated 属性需要在领域内设置。它应该是持久性无关的(因此数据库列中没有“默认”值等)。 - EkoostikMartin
1
@Aphelion - 非常好的观点,我也在考虑同样的事情,尽管每个子类都需要实现LastUpdated属性。只是试图避免这种情况。我认为这取决于具体的对象模型,尽管你的方法显然更灵活。 - EkoostikMartin
1
那么,为什么带有泛型的模型不起作用呢?我可以将 PersistableObject<Cat, CatKey> 传递给我的 DAO,同时仍然拥有一个原始的 Cat 模型。 - Kev
@EkoostikMartin 在我看来,这将是对泛型的误用。顺便问一下,在你的泛型定义中,K代表什么? - Myrtle
@EkoostikMartin,我认为Aphelion的回答最好。如果你将你的回答更新为接口回答,我会将其标记为答案。 - Kev
显示剩余5条评论

1
我会尽力而为。我认为您可能将对象与记录混淆了。“上次更新日期”不是指猫的更新时间,而是指记录的更新时间。在面向对象编程中,自然而然地认为可以将有关该对象的所有内容封装在一个对象中。但是,一个对象本身并没有表达任何上下文。即使在您的猫中,您也有颜色类型,如果没有一种方法来获取rgb或cmyk值,那么它本身就什么都不是。
在OO的第一天,其中一个示例教练展示了猫是动物,动物是生命体等等。在您的域对象中加入“上次修改时间”没有任何问题,甚至“上次更新者”大多数情况下也是一个好选择。但是,如果您能够分离和建模对象如何与其他对象交互以及如果它们具有过多定义时将受到限制(是的,我说过受限制,因为它已经对很多事情做出了决定),那么这样做是没有问题的。我并不是试图建议过度思考对象的重用,但是适当的关系对于模型非常重要,因为您应该能够在10英尺或10000英尺的视角提供上下文和含义。

我在平台研发领域工作了将近9年,建模和开发跨越多年的平台。我们遇到的最大问题就是把一个或两个ia-a和has-a关系搞反了。这会使模型变得无用,与其这样,不如直接使用拥有200列的平面表,但即便如此,在大型甚至小型模型中重构几个关系也是一个重大挫折。对象不是记录,甚至不是类,它们是赋予数据意义的东西。

简而言之,MyBizObject扩展了MyBizRecord,这是所有书籍都推荐的方法,但是MyBizProduct...扩展了MyBizMaterial,数组MyBizRecord[] changeHistory;...更加强大,如果有一天需要添加MyBizOrders[]作为历史记录,您不必重新设计整个模型和工厂。我相信这不是您期望阅读的内容,但我希望它能引发您寻找答案的思考。


它确实能够启动思路。我感谢你抽出时间来回答。 - Kev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接