EAA P中的域模型和服务层模式 [英] Domain Model and Service Layer patterns in P of EAA

查看:438
本文介绍了EAA P中的域模型和服务层模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In Patterns of Enterprise Application Architecture, Martin Fowler talks about two patterns for organizing Domain Logic: Domain Model and Service Layer. The Domain Model pattern is the "pure OOP" approach, where models (those objects that are probably being looked up from the database using an ORM) contain business logic (albeit, probably only delegating to the logic in another class).

服务层"模式类似于域模型"模式,但是在其前面有一个薄层,其中包含可以执行的业务操作.在MVC中,控制器通常会与服务层进行交互.我相信大多数设计良好的MVC Web应用程序都使用这种模式.

The Service Layer pattern is like the Domain Model pattern, but with a thin layer in front of it containing the business operations that can be performed. In MVC, the controller would mostly interact with the Service Layer. I believe that most well-designed MVC web applications use this pattern.

现在,我的问题.马丁建议域模型方法是更面向对象的方法,因此更好.以我的经验,在实践中很难实施(见:不可能).

Now, to my question. Martin suggests that the Domain Model approach is the more object-oriented approach, and is therefore better. In my experience, it is very difficult (see: impossible) to implement in practice.

以上面第一张图中给出的示例为例.有两个实体" ContractProduct.这些通过映射器持久化到数据库中.在示例中,有一个RecognitionStrategy.马丁将用于委派该策略的方法放到实体本身中,该策略包含实际的业务逻辑.客户端使用contract.calculateRecognitionscontract.recognizedRevenue(someDate)执行此计算.在实现类似设计时,我通常将客户端接口编写为strategy.calculateRecognitions(contract)strategy.recognizedRevenue(contract, someDate).这使得服务层对于协调策略和合同是必需的.所使用的具体策略已注入服务中.

Take the example given in the first diagram above. There are two "entities" Contract and Product. These are persisted to the database with a mapper. In the example, there is a RecognitionStrategy. Martin puts the methods for delegating to this strategy, which contains the actual business logic, in the entities themselves; the client performs this calculation with contract.calculateRecognitions or contract.recognizedRevenue(someDate). When implementing similar designs, I usually write the client interface as strategy.calculateRecognitions(contract) and strategy.recognizedRevenue(contract, someDate). This makes the service layer necessary for coordinating the strategy and contract. The concrete strategy used is injected into the service.

从设计的角度来看,马丁的方法绝对更具吸引力,但围绕设置的工作却要困难得多:

Martin's approach is definitely more appealing from a design perspective, but the work around the setup is much more difficult:

  1. 实例化Product时传递策略是很痛苦的.您需要通过带有具体服务的工厂来创建Product,使用该服务时,它将在创建时将其传递到实体中.
  2. 对数据库访问的粒度控制较少.根据ORM设置,委派给ProductContract可能会按Product执行查询.当我们加载Contract但不打算调用contract.calculateRecognitions()时,贪婪地将Product s加载到映射器(或ORM)中可能会太过热情.我的方法为我们提供了更细粒度的控制,因为该服务具有数据库抽象层的知识,而实体则不应该.
  1. Passing in the strategy when instantiating a Product is a pain. You need to create Products via a factory curried with the concrete service to use, which will in turn pass it into the entity when creating it.
  2. Less fine-grained control over database access. Depending on the ORM settings, the Contract delegating to Product may perform a query per Product. Greedily loading Products in the mapper (or ORM) may be overzealous when we load a Contract but don't intend to call contract.calculateRecognitions(). My approach gives us finer-grained control, because the service has knowledge of the database abstraction layer, where as the entities shouldn't.

我敢肯定,在实践中还有更多的痛点我没有在这里列举.

I'm sure there are more pain points in practice that I haven't enumerated here.

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

What concrete advantages are there in Martin's approach that might convince me to use a pure Data Model pattern?

推荐答案

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

Regarding your first point, you should use dependency injection when instantiating the Product object. Object graph construction is a full flagged responsibility and should not be mixed with your business logic (single responsibility principle).

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

Regarding the second point, your vendor particularities should be hidden behind you data access layer and your DAO or Repository should return the objects according to your needs.

您担心如何贪婪地加载Product s(在这种关系是一对多的情况下)的另一种选择是将Product DAO注入到Contract对象中.通过这种方法,您可以在需要时获得与合同相关的Product(可能是在也可以在内部使用的吸气剂上).

An alternative for your concern over greedily loading Product s (on a situation the relationship is one to many) is to have the Product DAO injected into the Contract object. With that approach you could get the Product s related to the contract when required (probably on a getter that could also be used internally).

当然,不存在完美的解决方案,并且总会存在权衡取舍.您作为建筑师的工作是评估更适合您的应用程序的方法.

Of course a perfect solution does not exist and there will always be trade offs. Your job as an architect to evaluate the approach that better fits you application.

根据我的亲身经历,我注意到过多地依赖服务类往往会生成巨大的类,这些类没有明确的职责,而且通常很难测试.

On my personal experience I noticed that relying too much on service classes tends to generate gigantic classes that don't have a well defined responsibility and are usually too difficult to test.

因此,使用域模型方法的好处是可以将关注点清楚地分开并提高可测试性.

So benefits of using the Domain Model approach are clear separation of concerns and increased testability.

最后,您不需要使用纯"域模型方法.领域模型和服务层预计将一起使用. 域模型实体覆盖了其边界内的行为,而服务层覆盖逻辑则不属于任何域实体.

Finally you don't need to use a "pure" Domain Model approach. The domain model and service layer are expected to be used together. The domain model entities cover behaviors that fall within their boundaries and the service layer cover logic doesn't belong in any domain entity.

您可能会发现有趣的其他参考

Some additional reference you may find interesting

实践中的域驱动设计和开发-有关DDD的有趣文章

依赖注入,使用Spring和Guice设计模式-关于依赖注入的好书

此致

伊曼纽尔·路易斯·拉里格特·贝尔特拉姆

Emanuel Luiz Lariguet Beltrame

这篇关于EAA P中的域模型和服务层模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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