贫血数据模型,dao's,...权威参考?

时间:2013-10-22 14:26:02

标签: oop architecture

虽然是经验丰富的程序员和架构师,但同样的旧基本问题反复出现。我有自己的宗教信仰,但我需要一些权威来源。

贫血数据模型((c)Martin Fowler?)本质上是不好的?蛋糕应该能够自己烘烤吗?发票应该知道如何(以及何时应该允许)向自己添加行,或者另一层应该这样做? rabbit.addToHole(洞)或hole.addRabbit(兔子)?是否已证明ADM更容易出错,或更容易维护,或其他什么?

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

2 个答案:

答案 0 :(得分:3)

请参阅此stackoverflow answer以获取启发。

这是我的观点:

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

表示

贫血领域模型很糟糕,只有完整的oop。它被认为是糟糕的设计,主要是因为你无法在其中创建UML类和与嵌入行为的关系。例如,在包含Rich Domain Model(RDM)的Invoice类中:

  • 班级名称:订单
  • 已实施:ICommittable,IDraftable,...
  • 属性:No,UserId,TotalAmount,...
  • 行为:Commit(),SaveDraft(),...

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

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

  

通常,您在服务中找到的行为越多,就越多   可能你要剥夺自己域名的好处   模型。如果你的所有逻辑都在服务中,你就会失明。

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

SRP

在ADM的观点和对继承的压缩中,RDM(富域模型)违反了SRP。这可能是真的,但您可以参考此question进行讨论。

很简单,从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,如果您的系统设计不好,维护都很困难。任何类型的电锯只有在熟练的木匠手持时才能发光。

答案 1 :(得分:-2)

我认为this question的接受答案也是最能回答您问题的答案。

我认为必须记住的事情是:

  • ADM适用于CRUD应用程序,并且由于大多数应用程序都是以这种方式启动的,因此它可以作为一个起始架构;如果需要,你可以通过重构从那里发展,但是从一开始就没有过度设计应用程序
  • 一旦复杂性开始增长 - 一旦业务规则开始堆积 - 保持模型贫乏不太方便 - 将规则与他们所处理的对象分开使得很难记住在查看对象时应用的所有规则
  • 如果规则在域对象中,它们也有助于编写测试,如果它们在其他地方(例如在无状态服务中),则不知道域对象可以做什么以及适用于哪些约束它是,为它编写适当的测试(认为在不同的服务中建模的正交规则)
  • 真正简单的应用程序和贫血领域模型之间存在区别:在一个非常简单的应用程序中,没有太多的业务逻辑,在贫乏的领域模型中存在逻辑,但是与域模型分开保存