贫血模式-AnemicDomainModel

研究DDD模式时,提到贫血模式,查看Martin Fowler

转自 https://martinfowler.com/bliki/AnemicDomainModel.html                     

                   

                           

这是已经存在很长时间的反模式之一,但目前似乎有一种特殊的突破。我正在和Eric Evans聊天,我们都注意到他们似乎越来越受欢迎了。作为一个适当的领域模型的伟大助推器,这不是一件好事。

贫血领域模型的基本症状是乍一看它看起来像真实的东西。有许多对象,其中许多以域空间中的名词命名,并且这些对象与真实域模型具有的丰富关系和结构相关联。当你看到这个行为时会发现这个问题,你会发现这些物体上几乎没有任何行为,这使得它们只不过是吸气剂和制定者的一部分。实际上,这些模型通常都带有设计规则,表明您不要将任何域逻辑放在域对象中。相反,有一组服务对象捕获所有域逻辑,执行所有计算并使用结果更新模型对象。这些服务位于域模型之上,并使用域模型进行数据。

这种反模式的根本恐怖之处在于它与面向对象设计的基本思想相悖;这是将数据和过程结合在一起。贫血领域模型实际上只是一种程序风格的设计,正是像我这样的偏执狂(和Eric)在我们早期的Smalltalk中一直在战斗的东西。更糟糕的是,许多人认为贫血物体是真实物体,因此完全忽略了面向对象设计的全部意义。

现在面向对象的纯粹主义一切都很好,但我意识到我需要更多基本的论据来对抗这种贫血症。从本质上讲,贫血领域模型的问题在于它们会产生领域模型的所有成本,而不会产生任何好处。主要成本是映射到数据库的尴尬,这通常导致整个O / R映射层。如果您使用强大的OO技术来组织复杂的逻辑,这是值得的。但是,通过将所有行为拉入服务,您最终会得到事务脚本,从而失去域模型可以带来的优势。正如我在EAA的P中所讨论的,域模型并不总是最好的工具。

值得强调的是,将行为放入域对象不应该与使用分层将域逻辑与持久性和表示责任等事物分离的可靠方法相矛盾。应该在域对象中的逻辑是域逻辑 - 验证,计算,业务规则 - 无论您喜欢什么称呼它。 (有些情况下您会将数据源或表示逻辑放在域对象中,但这与我对贫血的看法是正交的。)

所有这些混淆的一个原因是许多OO专家建议在域模型之上放置一层过程服务,以形成服务层。但这并不是使域模型无行为的论据,实际上服务层倡导者将服务层与行为丰富的域模型结合使用。

埃里克埃文斯的优秀书籍领域驱动设计有关于这些层的以下内容。

应用层[他的服务层名称]:定义软件应该执行的作业,并指示表达域对象解决问题。该层负责的任务对业务有意义,或者与其他系统的应用层交互所必需。该层保持薄。它不包含业务规则或知识,但只有协调任务和委托才能在下一层中协作域对象的协作。它没有反映业务情况的状态,但它可以具有反映用户或程序的任务进度的状态。

域层(或模型层):负责表示业务概念,业务情况信息和业务规则。反映业务情况的状态在此处受到控制和使用,即使存储它的技术细节被委托给基础设施。这一层是商业软件的核心。

这里的关键点是服务层很薄 - 所有关键逻辑都在域层中。他在服务模式中重申了这一点:

现在,更常见的错误是过于轻易地放弃将行为拟合到适当的对象中,逐渐滑向程序编程。

我不知道为什么这种反模式如此普遍。我怀疑这是因为许多人没有真正使用适当的域模型,特别是如果他们来自数据背景。一些技术鼓励它;比如J2EE的Entity Beans,这是我更喜欢POJO域模型的原因之一。

一般而言,您在服务中发现的行为越多,您就越有可能剥夺自己对域模型的好处。

       

 

原文

 

This is one of those anti-patterns that's been around for quite a long time, yet seems to be having a particular spurt at the moment. I was chatting with Eric Evans on this, and we've both noticed they seem to be getting more popular. As great boosters of a proper Domain Model, this is not a good thing.

The basic symptom of an Anemic Domain Model is that at first blush it looks like the real thing. There are objects, many named after the nouns in the domain space, and these objects are connected with the rich relationships and structure that true domain models have. The catch comes when you look at the behavior, and you realize that there is hardly any behavior on these objects, making them little more than bags of getters and setters. Indeed often these models come with design rules that say that you are not to put any domain logic in the the domain objects. Instead there are a set of service objects which capture all the domain logic, carrying out all the computation and updating the model objects with the results. These services live on top of the domain model and use the domain model for data.

The fundamental horror of this anti-pattern is that it's so contrary to the basic idea of object-oriented design; which is to combine data and process together. The anemic domain model is really just a procedural style design, exactly the kind of thing that object bigots like me (and Eric) have been fighting since our early days in Smalltalk. What's worse, many people think that anemic objects are real objects, and thus completely miss the point of what object-oriented design is all about.

Now object-oriented purism is all very well, but I realize that I need more fundamental arguments against this anemia. In essence the problem with anemic domain models is that they incur all of the costs of a domain model, without yielding any of the benefits. The primary cost is the awkwardness of mapping to a database, which typically results in a whole layer of O/R mapping. This is worthwhile iff you use the powerful OO techniques to organize complex logic. By pulling all the behavior out into services, however, you essentially end up with Transaction Scripts, and thus lose the advantages that the domain model can bring. As I discussed in P of EAA, Domain Models aren't always the best tool.

It's also worth emphasizing that putting behavior into the domain objects should not contradict the solid approach of using layering to separate domain logic from such things as persistence and presentation responsibilities. The logic that should be in a domain object is domain logic - validations, calculations, business rules - whatever you like to call it. (There are cases when you make an argument for putting data source or presentation logic in a domain object, but that's orthogonal to my view of anemia.)

One source of confusion in all this is that many OO experts do recommend putting a layer of procedural services on top of a domain model, to form a Service Layer. But this isn't an argument to make the domain model void of behavior, indeed service layer advocates use a service layer in conjunction with a behaviorally rich domain model.

Eric Evans's excellent book Domain Driven Design has the following to say about these layers.

Application Layer [his name for Service Layer]: Defines the jobs the software is supposed to do and directs the expressive domain objects to work out problems. The tasks this layer is responsible for are meaningful to the business or necessary for interaction with the application layers of other systems. This layer is kept thin. It does not contain business rules or knowledge, but only coordinates tasks and delegates work to collaborations of domain objects in the next layer down. It does not have state reflecting the business situation, but it can have state that reflects the progress of a task for the user or the program.

Domain Layer (or Model Layer): Responsible for representing concepts of the business, information about the business situation, and business rules. State that reflects the business situation is controlled and used here, even though the technical details of storing it are delegated to the infrastructure. This layer is the heart of business software.

 

The key point here is that the Service Layer is thin - all the key logic lies in the domain layer. He reiterates this point in his service pattern:

Now, the more common mistake is to give up too easily on fitting the behavior into an appropriate object, gradually slipping toward procedural programming.

 

I don't know why this anti-pattern is so common. I suspect it's due to many people who haven't really worked with a proper domain model, particularly if they come from a data background. Some technologies encourage it; such as J2EE's Entity Beans which is one of the reasons I prefer POJO domain models.

In general, the more behavior you find in the services, the more likely you are to be robbing yourself of the benefits of a domain model. If all your logic is in services, you've robbed yourself blind.

 

posted on 2019-02-23 15:49  持续在更新  阅读(761)  评论(0编辑  收藏  举报

导航