2

尽管是一位经验丰富的程序员和架构师,但同样的老基本问题会反复出现。我对此有自己的信仰,但我需要一些权威来源。

贫血的数据模型((c)Martin Fowler?)天生就不好吗?蛋糕应该可以自己烤吗?发票是否应该知道如何(以及何时应该允许)向自身添加行,还是应该由另一层来执行?rabbit.addToHole(hole) 还是hole.addRabbit(rabbit)?是否已经证明 ADM 更容易出错,或者更容易维护,或者其他什么?

你可以在网上找到很多说法,但如果可能的话,我真的想要一些权威的引用、参考或事实。

4

2 回答 2

3

请参阅此stackoverflow 答案以获得启发。

这是我的看法:

ADM(贫血领域模型)不能用类图 UML 表示

贫血域模型不好,仅在完整的 oop 方面。它被认为是糟糕的设计,主要是因为您无法创建 UML 类和在其中嵌入行为的关系。例如,在具有富域模型 (RDM) 的 Invoice 类中:

  • 班级名称:订单
  • 已实现:ICommittable、IDraftable、...
  • 属性:否,UserId,TotalAmount,...
  • 行为:提交(),SaveDraft(),...

该课程是自我记录的,并自我解释它可以做什么和不能做什么。

如果是贫血的领域模型,它是没有行为的,我们需要搜索哪个类负责提交和保存草稿。而且由于 UML 类图只显示了每个类之间的关系(一对多/多对多/聚合/复合),因此无法记录与服务类的关系,Martin Fowler 的观点是正确的。

通常,您在服务中发现的行为越多,您就越有可能剥夺自己从领域模型中获得的好处。如果您的所有逻辑都在服务中,那么您已经蒙蔽了自己。

这是基于 OOAD 书中的类图 UML Lars Mathiassen。我不知道更新的类图 UML 是否可以表示服务类。

建议零售价

从 ADM 的观点和继承的角度来看,RDM(富域模型)违反了 SRP。这可能是真的,但你可以参考这个问题进行讨论。

简而言之,在 ADM 的观点中,SRP 等于一个班级做一件事且只做一件事。Any change into the class has one and only one reason.

在 RDM 的观点中,SRP 等同于所有与接口本身相关的责任。一旦操作涉及到其他类,则需要将操作放到其他接口中。实现本身可能会有所不同,例如,如果一个类可以实现 2 个或更多接口。简称为if an operation in interface need to be changed, it is for and only for one reason

ADM 往往被静态方法滥用,并且可能适用肮脏的黑客攻击

ADM 很容易被静态方法——服务类滥用。它也可以用 RDM 完成,但它需要另一层抽象,不值得。静态方法通常是糟糕设计的标志,它降低了可测试性,并可能引入竞争条件,以及隐藏依赖关系。

ADM 可能有许多肮脏的技巧,因为操作不受对象定义的限制(嘿,我可以为此创建另一个类!)。在糟糕的设计师手中,这可能会成为灾难性的。在 RDM 中更难,请阅读下一点以获取信息。

RDM 的实现通常不能重用,也不能模拟。RDM 需要事先了解系统的行为

通常 RDM 的实现不能被重用和模拟。在 TDD 方式中,它降低了可测试性(如果有可以模拟和重用的 RDM,请纠正我)。想象一下这个继承树的情况:

    A
   / \
  B   C

如果 B 需要在 C 中实现逻辑,则无法完成。使用组合而不是继承,可以实现。在 RDM 中,可以通过这样的设计来完成:

    A
    |
    D
   / \
  B   C

其中引入了更多的继承。但是,为了尽早实现整洁的设计,您需要直接了解系统流程。也就是说,RDM 要求您在进行任何设计之前了解系统的行为,否则您将不知道任何适合您系统的名为 ISubmitable、IUpdateable、ICrushable、IRenderable、ISoluble 等的接口。

结论

这就是我对这种圣战的全部看法。两者都有优点和缺点。我通常选择 ADM,因为它似乎更高的灵活性甚至更低的可靠性。不管是 ADM 还是 RDM,如果你的系统设计不好,维护就会很困难。任何类型的电锯只有在熟练的木匠手握时才会发光。

于 2013-10-23T02:53:27.790 回答
-2

我认为这个问题的公认答案也是最好的回答你的问题。

我认为必须记住的事情:

  • ADM 对于 CRUD 应用程序来说已经足够了,而且由于大多数应用程序都是以这种方式启动的,因此它可以作为启动架构;如果需要,您可以通过重构从那里发展,但是从一开始就过度设计应用程序没有意义
  • 一旦复杂性开始增长 - 一旦业务规则开始堆积 - 保持模型贫乏就不太方便 - 将规则与它们所作用的对象分开会使您在查看对象时很难记住所有适用的规则
  • 如果规则在域对象中,它们也有利于编写测试,如果它们在其他地方(比如在无状态服务中),你不知道域对象可以做什么以及适用于它的所有约束是什么,为它编写适当的测试(想想在不同服务中建模的正交规则)
  • 真正简单的应用程序和贫血的领域模型之间有区别:在真正简单的应用程序中,没有太多业务逻辑,在贫血的领域模型中,逻辑存在,但与领域模型分开保存
于 2016-08-02T12:02:35.930 回答