mot*_*sch 13 design-patterns architectural-patterns service-layer anemic-domain-model
在企业应用程序架构模式中,Martin Fowler讨论了组织域逻辑的两种模式:域模型和服务层.域模型模式是"纯OOP"方法,其中模型(可能使用ORM从数据库中查找的那些对象)包含业务逻辑(尽管可能仅委托给另一个类中的逻辑).
服务层模式类似于域模型模式,但前面有一个薄层,包含可以执行的业务操作.在MVC中,控制器主要与服务层交互.我相信大多数精心设计的MVC Web应用程序都使用这种模式.
现在,我的问题.Martin建议域模型方法是面向对象的方法,因此更好.根据我的经验,在实践中实施非常困难(见:不可能).
以上面第一个图中给出的例子为例.有两个"实体" Contract
和Product
.这些使用映射器持久保存到数据库.在这个例子中,有一个RecognitionStrategy
.Martin在实体本身中提出了委托此策略的方法,该策略包含实际的业务逻辑; 客户端使用contract.calculateRecognitions
或执行此计算contract.recognizedRevenue(someDate)
.在实现类似设计时,我通常将客户端接口编写为strategy.calculateRecognitions(contract)
和strategy.recognizedRevenue(contract, someDate)
.这使得服务层成为协调战略和合同所必需的.使用的具体策略注入服务.
从设计的角度来看,Martin的方法肯定更具吸引力,但围绕设置的工作要困难得多:
Product
是一种痛苦.您需要Product
通过一个使用具体服务的工厂创建s,然后在创建它时将其传递给实体.Contract
委托Product
可以执行查询Product
.Product
当我们加载a Contract
但不打算调用时,在mapper(或ORM)中贪婪地加载s可能过于热心contract.calculateRecognitions()
.我的方法为我们提供了更细粒度的控制,因为服务具有数据库抽象层的知识,而实体则不应该知道.我确信在实践中还有更多的痛点,我在这里没有列举.
Martin的方法有哪些具体优势可能说服我使用纯数据模型模式?
小智 6
关于第一点,在实例化Product对象时应该使用依赖注入.对象图构造是一个完全标记的责任,不应与您的业务逻辑混合(单一责任原则).
关于第二点,您的供应商特性应隐藏在数据访问层后面,您的DAO或存储库应根据您的需要返回对象.
贪婪地加载Product(在关系是一对多的情况下)的另一个选择是将Product DAO注入Contract对象.使用这种方法,您可以在需要时获得与合同相关的产品(可能是在内部也可以使用的吸气剂).
当然,不存在完美的解决方案,总会有折衷.您作为架构师的工作,评估更适合您应用的方法.
根据我的个人经验,我注意到过分依赖服务类往往会产生巨大的类,这些类没有明确的责任,通常很难测试.
因此,使用域模型方法的好处是明确区分关注点和提高可测试性.
最后,您不需要使用"纯"域模型方法.期望域模型和服务层一起使用.域模型实体涵盖属于其边界的行为,并且服务层覆盖逻辑不属于任何域实体.
您可能会发现一些有趣的其他参考
依赖注入,使用Spring和Guice设计模式 - 关于依赖注入的好书
问候,
Emanuel Luiz Lariguet Beltrame
Domain model represent an object as well as it's behavior better than anemic one. Because the behavior attached to it. Basic example is, a dog
can bark
, breathe
and eat
. In Service layer, the model are enhanced with BarkHandler
and BreatheHandler
.
Domain model approach are natively supported by UML design pattern. My previous answer here. For anemic domain model approach (service layer), it is hard to make a UML diagram (class diagram), and even if you had able to create one, it is not officially accepted so people will have different interpretation there.
In terms of design perspective, service layer is too "independent
" or separated. By looking at the anemic domain model class
, you cannot find the behavior (save, for example) related to the domain model. You need to search for entire project to find the specific behavior for the domain model. While in rich domain model, you know the traces of behavior inside the domain model itself.
Rich domain model have better access modifier (public, private, protected) for their properties. As well as property visibility. For example if you want to change status after submit, you can make the property get access to public
, but the set access to protected
. In service layer, you need to make the set access to public
, or trick it with internal protected
and make the submitter to directly change the property via internal access
. But it is an added complexity.
但富域模型不具备这样的灵活性anemic domain model
。除非使用继承,否则您无法在不更改域模型的类的情况下向模型添加行为。在贫血域模型中,您甚至可以在运行时级别交换它。