域驱动设计 – DDD,存储库和封装
如果有人认为这是殴打死亡,我提前道歉.我在过去几个小时里花了几个小时在这里搜索和阅读了很多优秀的帖子,但我仍然感到困惑.
我的困惑的根源是DTO与DDD和存储库.我想要我的POCO域对象拥有智能,我想从存储库获取它们.但是,似乎我必须违反一些封装规则来完成这项工作,而且似乎可以把DTO转到头上. 这是一个简单的例子:在我们的目录应用程序中,Part可以是包含许多其他部分的包.所以,Part POCO有一个’GetChildren()’方法返回IEnumerable&部分>.甚至可能在其出路上列出其他的东西. 但是该列表如何解决?似乎就是存储库的答案: interface IPartRepository : IRepository<Part> { // Part LoadByID(int id); comes from IRepository<Part> IEnumerable<Part> GetChildren(Part part); } 和 class Part { ... public IEnumerable<Part> GetChildren() { // Might manipulate this list on the way out! return partRepository.GetChildren(this); } } 所以现在我的目录的消费者除了(正确地)从仓库中加载零件之外,还可以通过直接调用GetChildren(part)来绕过某些部件封装的逻辑.不是那么糟糕吗 我读到这个存储库应该提供POCO,但DTO对于在层之间传输数据是有好处的.计算了很多部件属性,例如,价格是根据复杂的定价规则计算的.价格甚至不会出现在存储库中的DTO中 – 所以看起来将定价数据传递回网络服务需要DTO消耗零件,而不是相反. 这已经太长了我的头在哪里松开?
解决这个问题的一种方法是将逻辑本身移动到子部件中 – 也就是改变类的语义,以使Part对象在与父级关联时负责转换自身.
例如,如果零件的价格取决于其零部件,价格可以在以下时间(至少)确定: >建造时,如果父母部分(和所有其他必要的数据)可用. 编辑:我原来的答案(下)真的不是DDD的精神.它涉及到域对象简单的容器,许多被认为是反模式的设计(见Anemic Domain Model). Part和IPartRepository之间的一个附加层(我将其称为IPartService)解决了这个问题:将GetChildren(part)移动到IPartService中,并将其从Part中移除,然后使客户端代码调用IPartService来获取Part对象及其子代,而不是击中存储库直接. Part类还有一个ChildParts(或Children)属性 – 它不知道如何自己填充它. 显然,这会增加额外的成本 – 如果在大多数情况下不需要额外的业务逻辑,您可能会最终编写或生成许多用于存储库调用的传递代码. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |