n8w*_*wrl 10 domain-driven-design poco repository-pattern
如果人们认为这已被打死,我会提前道歉.我刚刚花了几个小时在这里搜索和阅读很多优秀的帖子,但我仍然感到困惑.
我混淆的根源是DTO与DDD和存储库.我希望我的POCO域对象具有智能,我想从存储库中获取它们.但似乎我必须违反一些封装规则才能使其工作,而且似乎它可以将DTO转变为他们的头脑.
这是一个简单的例子:在我们的目录应用程序中,Part可以是包含许多其他部分的包.因此,Part POCO有一个'GetChildren()'方法返回IEnumerable <Part>是有道理的.它甚至可能会在列表中出现其他内容.
但该清单如何解决?似乎存储库就是答案:
interface IPartRepository : IRepository<Part>
{
// Part LoadByID(int id); comes from IRepository<Part>
IEnumerable<Part> GetChildren(Part part);
}
Run Code Online (Sandbox Code Playgroud)
和
class Part
{
...
public IEnumerable<Part> GetChildren()
{
// Might manipulate this list on the way out!
return partRepository.GetChildren(this);
}
}
Run Code Online (Sandbox Code Playgroud)
所以现在我的目录的使用者除了(正确地)从存储库加载部件之外,还可以通过直接调用GetChildren(部分)来绕过一些部分封装的逻辑.不是那么糟糕吗?
我读到存储库应该提供POCO,但DTO适用于在层之间传输数据.计算了许多零件属性 - 例如,价格是根据复杂的定价规则计算的.价格甚至不会来自存储库的DTO - 因此将定价数据传递回Web服务似乎需要DTO使用Part,而不是相反.
这已经太长了.拧开我的头在哪里?
解决此问题的一种方法是将逻辑移至子部分本身,即更改类的语义,以便Part对象在与父对象关联时负责转换自身。
例如,如果 a 的价格Part取决于其父级Part,则可以在以下时间(至少)确定价格:
构建后,如果父级Part(以及所有其他必要的数据)可用。
在AttachToParent(Part parentPart)方法中或响应事件,即OnAttachedToParent(Part parentPart)。
当客户端代码需要它时(即,在第一次访问其Price属性时)。
编辑:我原来的答案(如下)确实不符合 DDD 的精神。它涉及使域对象成为简单的容器,这种设计被许多人认为是一种反模式(请参阅贫血域模型)。
Part和之间的附加层IPartRepository(我将其称为IPartService)解决了这个问题:将其移入GetChildren(part)并IPartService从中删除Part,然后进行客户端代码调用IPartService以获取Part对象及其子对象,而不是直接访问存储库。该类Part仍然有一个ChildParts(或Children) 属性 - 它只是不知道如何填充它本身。
显然,这会带来额外的成本 - 如果在大多数情况下不需要额外的业务逻辑,您最终可能会编写或生成大量用于存储库调用的传递代码。
| 归档时间: |
|
| 查看次数: |
2205 次 |
| 最近记录: |