依赖注入 – 域驱动设计和IoC /依赖注入
我现在试图应用我对DDD的了解,我对域模型中的依赖关系有一点疑惑.
我的问题是: >实体应该知道域中的工厂,存储库,服务? 另一件令我心烦的事情是,当我想要添加和实体到集合时,如何对待集合. 假设我正在开发一个简单的CMS.在CMS中,我有一个包含标签实体的文章实体和标签集合. 现在,如果我想添加一个与新标签的关系.什么是更好的方法呢? (PHP中的示例) $article->tags->add(TagEntity); $articleRepository->save($article); 或者我可以做一个服务. $articleService->addTag($article,TagEntity); 你怎么看? 谢谢.
实体和价值对象不应该依赖于彼此之外的任何东西.这些都是
building blocks of DDD最基础的,它们代表了你的问题领域的概念,因此应该把重点放在这个问题上.通过使它们依赖于工厂,存储库和服务您使焦点模糊.在“实体”和“值对象”中引用“服务”还有一个问题.因为服务还具有领域逻辑您将被诱惑将域模型的一些责任委托给最终可能导致
Anemic Domain Model的服务.
工厂和存储库只是用于实体的创建和持久化的助手.大多数时候,他们在真正的问题领域只是没有类比,所以从工厂和仓库到服务和实体的引用根据域逻辑是没有道理的. 关于你提供的例子,这是我如何实现的 $article->addTag($tag); $articleRepository->save($article); 我不会直接访问基础集合,因为我可能希望文章在添加到集合之前,在标签上执行一些域逻辑(强制约束,验证). 避免这个 $articleService->addTag($article,$tag); 仅使用服务来执行不属于任何Entity概念的操作.首先,尝试将其适用于实体,确保它不适合任何.然后只能使用一个服务.这样你不会得到贫血域模型. 更新1 埃里克·埃文斯的“领域驱动设计:解决软件中心的复杂性”的报价书:
更新2 有人下了这个答案,我不知道为什么.我只能怀疑原因.它可以是实体和服务之间的引用,也可以是示例代码.嗯,我不能做很多关于示例代码,因为我的意见是基于我自己的经验.但是,我对引用部分做了更多的研究,这里是我想出来的. 我不是唯一认为从实体引用服务,存储库和工厂不是一个好主意.我在这里发现了类似的问题: > Is it ok for entities to access repositories? 还有一些关于这个问题的好文章,特别是这个How not to inject services in entities,也提出了一个解决方案,如果你迫切需要调用一个名为Double Dispatch的实体的服务.这里是一个从PHP移植到PHP的文章的例子: interface MailService { public function send($sender,$recipient,$subject,$body); } class Message { //... public function sendThrough(MailService $mailService) { $subject = $this->isReply ? 'Re: ' . $this->title : $this->title; $mailService->send( $this->sender,$this->recipient,$this->getMessageBody($this->content) ); } } 因此,您可以看到,您没有引用MessageService实体中的MailService服务,而是作为参数传递给实体的方法.在http://devlicio.us/的评论文章中,本文作者“DDD: Services”提出了同样的解决方案. 我也试图看看埃里克·埃文斯在他的“领域驱动的设计:解决软件中的复杂性”一书中所说的这一点.简要搜索后,我没有找到确切的答案,但是我发现一个实体静态地调用该服务的例子,那就是没有引用它. public class BrokerageAccount { String accountNumber; String customerSocialSecurityNumber; // Omit constructors,etc. public Customer getCustomer() { String sqlQuery = "SELECT * FROM CUSTOMER WHERE" + "SS_NUMBER = '" + customerSocialSecurityNumber + "'"; return QueryService.findSingleCustomerFor(sqlQuery); } public Set getInvestments() { String sqlQuery = "SELECT * FROM INVESTMENT WHERE" + "BROKERAGE_ACCOUNT = '" + accountNumber + "'"; return QueryService.findInvestmentsFor(sqlQuery); } } 以下说明如下:
如果您看到上面提到的DDDSample项目的源代码,您将看到实体没有任何引用,除了模型包中的对象,即实体和值对象.顺便说一下,DDDSample项目在“域驱动设计:软件核心应对复杂性”一书中有详细描述… 此外,我想和你分享一件事也是一个类似的讨论 结论 总而言之,参考服务,实体库和工厂不是很好.这是最接受的意见.即使存储库和工厂是域层的公民,它们也不是问题域的一部分.有时(例如在维基百科的DDD文章中),域服务的概念称为Pure Fabrication,这意味着类(Service)“不代表问题域中的概念”.我宁愿将工厂和存储库称为纯粹制造,因为埃里克·埃文斯(Eric Evans)在他的书中提到了有关服务概念的其他内容:
根据上述说法,有时候从你的实体调用服务可能是一个理想的事情.然后,您可以使用Double Dispatch方法,以便您不必在Entity类中保留对Service的引用. 当然,总是有人不喜欢Accessing Domain Services from Entities文章的主流意见. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |