EAA中P的域模型和服务层模式

时间:2014-03-02 19:50:19

标签: design-patterns service-layer architectural-patterns anemic-domain-model

在企业应用程序架构模式中,Martin Fowler讨论了组织域逻辑的两种模式:Domain ModelService Layer。域模型模式是“纯OOP”方法,其中模型(可能使用ORM从数据库中查找的那些对象)包含业务逻辑(尽管可能仅委托给另一个类中的逻辑)。

A sample Domain Model

服务层模式类似于域模型模式,但前面有一个薄层,包含可以执行的业务操作。在MVC中,控制器主要与服务层交互。我相信大多数精心设计的MVC Web应用程序都使用这种模式。

A sample Service Layer

现在,我的问题。 Martin建议域模型方法是面向对象的方法,因此更好。根据我的经验,在实践中实施非常困难(见:不可能)。

以上面第一张图中给出的例子为例。有两个“实体”ContractProduct。这些使用映射器持久保存到数据库。在示例中,有一个RecognitionStrategy。 Martin在实体本身中提出了委托此策略的方法,该策略包含实际的业务逻辑;客户端使用contract.calculateRecognitionscontract.recognizedRevenue(someDate)执行此计算。在实现类似设计时,我通常将客户端界面编写为strategy.calculateRecognitions(contract)strategy.recognizedRevenue(contract, someDate)。这使得服务层成为协调战略和合同所必需的。使用的具体策略注入服务。

从设计的角度来看,Martin的方法肯定更具吸引力,但围绕设置的工作要困难得多:

  1. 在实例化Product时传递策略是一种痛苦。您需要通过一个使用具体服务的工厂创建Product,然后在创建它时将其传递给实体。
  2. 对数据库访问的细粒度控制。根据ORM设置,委派给Contract的{​​{1}}可以按Product执行查询。当我们加载Product但不打算调用Product时,在映射器(或ORM)中贪婪地加载Contract可能过于热心。我的方法为我们提供了更细粒度的控制,因为服务具有数据库抽象层的知识,而实体则不应该这样。
  3. 我确信在实践中还有更多的痛点,我在这里没有列举过。

    Martin的方法有哪些具体优势可能说服我使用纯数据模型模式?

2 个答案:

答案 0 :(得分:6)

关于第一点,您应该在实例化Product对象时使用依赖注入。对象图构造是一个完全标记的责任,不应与您的业务逻辑混合(单一责任原则)。

关于第二点,您的供应商特性应该隐藏在数据访问层之后,您的DAO或存储库应该根据您的需要返回对象。

关于贪婪地加载Product(在关系是一对多的情况下)的关注的另一种方法是将Product DAO注入Contract对象。使用这种方法,您可以在需要时获得与合同相关的产品(可能是在内部也可以使用的吸气剂)。

当然,不存在完美的解决方案,总会有折衷方案。您作为建筑师的工作,以评估更适合您应用的方法。

根据我的个人经验,我注意到过分依赖服务类往往会产生巨大的课程,这些课程没有明确的责任,而且通常难以测试。

使用域模型方法的好处是明确区分关注点和提高可测试性。

最后,您不需要使用“纯”域模型方法。期望域模型和服务层一起使用。 域模型实体涵盖属于其边界的行为,并且服务层覆盖逻辑不属于任何域实体。

您可能会感兴趣的其他一些参考

Domain Driven Design and Development In Practice - An interesting article on DDD

Dependency Injection, Design patterns using Spring and Guice - Great book on dependency injection

此致

Emanuel Luiz Lariguet Beltrame

答案 1 :(得分:2)

域模型代表一个对象以及它的行为比贫血的更好。因为附加的行为。基本示例是,dog可以barkbreatheeat。在服务层中,模型通过BarkHandlerBreatheHandler进行了增强。

UML设计模式本身支持域模型方法。 My previous answer here。对于贫血领域模型方法(服务层),很难制作UML图(类图),即使你能够创建一个,它也没有被正式接受,所以人们会有不同的解释。

从设计角度来看,服务层太“independent”或分开。通过查看贫血域模型class,您无法找到与域模型相关的行为(例如,保存)。您需要搜索整个项目以查找域模型的特定行为。在富域模型中,您知道域模型本身内部的行为痕迹。

富域模型的属性具有更好的访问修饰符(public,private,protected)。以及财产可见性。例如,如果您想在提交后更改状态,则可以使该属性获得public的访问权限,但可以访问protected。在服务层中,您需要设置public的设置权限,或使用internal protected欺骗它,并使提交者通过internal access直接更改属性。但这是一个额外的复杂性。

anemic domain model的富域模型does not have the flexibility具有。除非使用继承,否则无法在不更改域模型的类的情况下向模型添加行为。在贫血领域模型中,您甚至可以在运行时级别交换它。

相关问题