如何避免贫穷的域名模式和保持分离的关注? [英] How to avoid Anemic Domain Models and maintain Separation of Concerns?

查看:86
本文介绍了如何避免贫穷的域名模式和保持分离的关注?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎决定让你的对象完全认识到他们在系统中的角色,并且仍然避免在数据库和服务层的领域模型中有太多依赖关系。



例如:假设我有一个具有修订历史的实体,以及数据引用的几个查找表,您的实体对象应该有方法从某些查找表获取详细信息,无论是通过提供对查找表行的访问,或者通过将方法委托给它们,但是为了做到这一点,它取决于数据库层来读取这些行的数据。此外,当实体被保存时,它不仅需要知道如何保存自身,还需要将条目保存到修订历史记录中。是否有必要将引用数十个不同的数据层对象和服务对象传递给模型对象?这似乎使得逻辑的复杂性远远超过将薄型模型传递给服务层对象,但我听说过许多聪明人推荐这种结构。

解决方案

真的很好的问题。我花了相当多的时间思考这些话题。



通过注意表达领域模型与分离问题之间的紧张关系,您将展现出很大的洞察力。这很像我问过的关于告诉不要求和单一责任原则



这是我对这个主题的看法。



域模型是贫血的,因为它不包含域逻辑。其他对象使用贫血域对象获取和设置数据。你所描述的并不像域名逻辑。可能是,但一般来说,查找表和其他技术语言是最有可能的术语,对我们来说意味着什么,但不一定是客户的任何内容。如果这是不正确的,请澄清。



无论如何,域对象本身的构造和持久性不应该包含在域对象本身中,因为它不是域逻辑。



所以要回答这个问题,不,你不应该注入一大堆非域对象/概念,如查找表和其他基础设施细节。这是一个问题的泄漏到另一个。来自域驱动设计的工厂和存储库模式最适合将这些问题与域模式本身区分开来。



但请注意,如果您没有任何域那么你最终会遇到贫血的领域对象,比如一些无聊的吸烟者和设置者,这是一种如何,这是一个不合时宜的写作程序java /rel =noreferrer。



那么你如何获得两个世界的最好呢?您如何将领域对象仅专注于域逻辑,同时保持UI,构造,持久性等方式?我建议您使用双重派发或某种形式的限制方法访问



这里有一个例子双发假设你有这行代码:

  entity.saveIn(repository); 

在您的问题中,saveIn()将具有关于数据层的各种知识。使用Double Dispatch,saveIn()执行此操作:

  repository.saveEntity(this.foo,this.bar,this.baz) ; 

存储库的saveEntity()方法具有如何保存数据的所有知识



除了此设置,您可以:

  repository.save(实体); 

只需调用

  entity.saveIn(本); 

我重读了这个,我注意到实体仍然很薄,因为它只是简单地分派它的持久性到存储库。但在这种情况下,实体应该是薄的,因为您没有描述任何其他域逻辑。在这种情况下,您可以说螺丝双发,给我附件。是的,你可以,但是,IMO它暴露了你的实体的实现方式太多了,而这些访问者是分散域逻辑的。我认为应该得到和设置的唯一的类是一个名字以访问者结尾的类。



我将很快包装它。就个人而言,我不用saveIn()方法写我的实体,因为我认为即使有一个saveIn()方法倾向于用分心来丢弃域对象。我使用朋友类模式,包私有访问,或者可以使用生成器模式



好的,我已经完成了正如我所说,我很痴迷这个话题。


It seems that the decision to make your objects fully cognizant of their roles within the system, and still avoid having too many dependencies within the domain model on the database, and service layers?

For example: Say that I've got an entity with a revision history, and several "lookup tables" that the data references, your entity object should have methods to get the details from some of the lookup tables, whether by providing access to the lookup table rows, or by delegating methods down to them, but in order to do so it depends on the database layer to read the data from those rows. Also, when the entity is saved, It needs to know not only how to save itself, but also to save entries into the revision history. Is it necessary to pass references to dozens of different data layer objects and service objects to the model object? This seems like it makes the logic far more complex to understand than just passing back and forth thin models to service layer objects, but I've heard many "wise men" recommending this sort of structure.

解决方案

Really really good question. I have spent quite a bit of time thinking about such topics.

You demonstrate great insight by noting the tension between an expressive domain model and separation of concerns. This is much like the tension in the question I asked about Tell Don't Ask and Single Responsibility Principle.

Here is my view on the topic.

A domain model is anemic because it contains no domain logic. Other objects get and set data using an anemic domain object. What you describe doesn't sound like domain logic to me. It might be, but generally, look-up tables and other technical language is most likely terms that mean something to us but not necessarily anything to the customers. If this is incorrect, please clarify.

Anyway, the construction and persistence of domain objects shouldn't be contained in the domain objects themselves because that isn't domain logic.

So to answer the question, no, you shouldn't inject a whole bunch of non-domain objects/concepts like lookup tables and other infrastructure details. This is a leak of one concern into another. The Factory and Repository patterns from Domain-Driven Design are best suited to keep these concerns apart from the domain model itself.

But note that if you don't have any domain logic, then you will end up with anemic domain objects, i.e. bags of brainless getters and setters, which is how some shops claim to do SOA / service layers.

So how do you get the best of both worlds? How do you focus your domain objects only domain logic, while keeping UI, construction, persistence, etc. out of the way? I recommend you use a technique like Double Dispatch, or some form of restricted method access.

Here's an example of Double Dispatch. Say you have this line of code:

entity.saveIn(repository);

In your question, saveIn() would have all sorts of knowledge about the data layer. Using Double Dispatch, saveIn() does this:

repository.saveEntity(this.foo, this.bar, this.baz);

And the saveEntity() method of the repository has all of the knowledge of how to save in the data layer, as it should.

In addition to this setup, you could have:

repository.save(entity);

which just calls

entity.saveIn(this);

I re-read this and I notice that the entity is still thin because it is simply dispatching its persistence to the repository. But in this case, the entity is supposed to be thin because you didn't describe any other domain logic. In this situation, you could say "screw Double Dispatch, give me accessors."

And yeah, you could, but IMO it exposes too much of how your entity is implemented, and those accessors are distractions from domain logic. I think the only class that should have gets and sets is a class whose name ends in "Accessor".

I'll wrap this up soon. Personally, I don't write my entities with saveIn() methods, because I think even just having a saveIn() method tends to litter the domain object with distractions. I use either the friend class pattern, package-private access, or possibly the Builder pattern.

OK, I'm done. As I said, I've obsessed on this topic quite a bit.

这篇关于如何避免贫穷的域名模式和保持分离的关注?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆