DDD:如何组织层?

ati*_*yar 35 domain-driven-design code-organization repository project-organization layer

我是软件开发的新手.我个人认为,分层体系结构是一种很好的方法,可以减少面向对象方法中软件开发过程中出现的复杂性,更不用说保持代码的有序性.现在,我遇到了一些DDD(Domain Driven Design)引入的问题.当然,初级水平的.
这就是 -
让我们说,我想构建一个应用程序来保存数据库中的"人"相关数据,并在wpf数据网格中显示人员详细信息(DDD绝对不适用于这种规模的应用程序,但只是为了简化像我一样的业余爱好者).所以,我设计了一个域类"Person",类似于 -

    public class Person
    {
        public Person(dataType paramA)
        {
            this.PropertyA = paramA;
        }

        private dataType _fieldA;
        public dataType PropertyA
        {
            //encapsulates _fieldA    
        }

        public dataType PropertyX
        {        
            //some code that manipulates private field    
        }

        private dataType MethodPQR(dataType param)
        {        
            //some code    
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在,我对DDD的理解说,架构(最简单的版本)应该如下(如果我错了,请纠正我) -
在此输入图像描述
注意:

  1. 我希望datagrid绑定到一些ObservableCollection,只是为了立即反映任何类型的更改.

  2. 它是一个wpf应用程序,但不一定是MVVM模式,我故意想使用后面的代码(我不知道后面的代码本身是代表应用程序层)

所以我的问题是 -

  1. 什么样的代码应该属于应用层?

  2. 我的猜测是,我绝对不应该将我的域对象(Person)的ObservableColletion绑定为datagrid的itmsSource.那么我应该从域对象中提取什么类型的对象,以及如何?

  3. 为了保持表示层对象和域层对象之间的解耦,可能存在类似的约定DataGrid.那么非"直接"方法是什么?

  4. 如果Code-Behind与应用层进行对话,那么应用层应该与存储库进行通信吗?但是,如果需要某种类型的域访问而不是与数据访问相关(可能不在此应用程序中,但它可能会发生,对吧?),应用层应该与哪个域人员层中的X人进行对话?

我知道我所有的问题和问题都是非常业余的.但它们确实是问题和问题.所以,如果有人有时间,任何回复都将受到赞赏.

编辑:我不确定Data Repository是否应该有域模型的引用.

Sis*_*hus 40

就更多"经典"DDD而言,域域对象通常不允许在域外的任何地方使用.但是,在表示层中不使用域对象并不是绝对的规则.例如,Naked Objects代表了一个直接使用域对象的思想流派.我自己主要坚持不直接使用域对象的哲学,所以我不熟悉他们建议的所有实践,我个人认为直接绑定到域对象会不明智,但是......请记住不是每个人都认为这是一项要求.

如果您不允许域本身之外的域对象,则通常使用DTO或数据传输对象,这些对象只是没有域行为的简单属性类.DTO通常完全镜像域模型结构,但不必如此.

业务逻辑应该在域模型中实现,因此应用层中的大部分内容涉及协调各种服务,通常是将数据传入和传出客户端应用程序.许多人为此使用某种形式的SOA或至少使用Web服务.这些调用存储库但还要求其他组件(如汇编程序)获取从存储库调用返回的域对象,并将属性值复制到DTO中,然后可以将其序列化并返回给调用者.调用者通常是演示者或控制者,但如果您不使用MVC或MVP,则调用者仍将在表示层中.反向行程更复杂 - UI可以发回代表更新的DTO或代表要添加的新对象的DTO.调解这些来回活动主要是应用层的目的.

就域层的"非数据访问"而言,有几个典型的例子.大多数人通常会将您可能会想到的"X"组件称为域服务.域服务与应用程序服务的区别在于它与域模型的接近程度以及实际业务逻辑的存在.

例如,如果某个应用程序涉及某种订单放置,实际上有两个问题 - 订单放置和订单履行.应用程序服务调解将配置订单放置到UI所需的数据传输,然后返回用户希望放置的订单.但这只是调解数据传输,而这正是应用服务的终结.然后,可能需要域服务来应用业务规则并构建实际履行该订单所需的其他域对象.

总的来说,我发现这是一个可以应用于许多场景的有用概念或隐喻 - 应用服务仅在请求提交方面促进某种类型的请求.另一方面,域服务促进了实际的请求实现.

我遇到或可以轻易想象的除了面向数据之外的唯一其他"访问"模式是面向过程的功能.在每个应用程序中都没有遇到这种情况,但在某些领域中很常见.例如,在我工作的医疗保健中,您可能希望应用程序包含管理临床数据和临床过程的重要元素.我解决了这个问题,没有让该过程强调我的域模型的一部分,而是使用不同的工具.

OOP技术本身并不适合实际的过程,它们对于向进程提供数据和从进程捕获数据非常有用.面向对象毕竟也主要是面向名词的.对于实时流程管理,您需要"动词导向编程"而不是"面向名词的编程".工作流工具是"动词导向"工具,可以与域驱动模型互补,适用于数据密集型和流程密集型应用程序.我做了大量涉及C#DDD模型和Workflow Foundation模型的工作,但这仅适用于某些类型的应用程序.许多典型的商业应用程序只需要域模型和服务.

最后,DDD最重要的方面不是任何技术或架构.它的真正核心在于无所不在的语言,并与(通过我强烈的DIRECT交互)领域专家进行互动,以提炼出关键的领域知识.(在我看来,大多数声称做DDD的公司都没有,因为很多公司拒绝允许业务和开发直接进行交互,但这是另一个话题......)它是领域知识的提取和整合,而不是任何实际上将DDD与传统OOP分开的技术,也就是DDD的真正价值出现的地方.

编辑

就存储库的使用而言,图表是正确的.通常,应用程序层始终通过域对象的存储库.首先,您必须能够将数据带入应用程序,并且大多数应用程序还需要一定程度的查询能力.

领域层OTOH通常不会与存储库交互.通常,您希望域模型是自包含的,并且与任何特定技术分离,即它应该代表"纯域知识".持久性本质上与某种特定技术紧密耦合,因此通常人们努力使其域模型不受任何持久性实现的影响.您有存储库,但通常不希望在域模型中调用存储库方法.

在域模型本身内,对象可以作为新对象(可以直接实例化或通过工厂实例化)获得,也可以通过遍历关联获得.有时,在创建新对象时,将所需的所有内容传递给构造函数是不切实际的,因此这是一种在域模型本身中可能需要某种数据访问的情况.通常人们通过接口传递数据服务,以便可以为域模型提供数据访问,但仍然与数据层实现分离.但是在大多数情况下,域对象会与已经实例化的其他域对象进行操作和交互.

  • 对于这个例子,我只是在Person对象中有规则.虽然没有人回答.始终尝试将实体保持在有效状态.哪里放逻辑可以有所不同.一个备受争议的话题 - 谷歌"DDD中的验证",以查看意见/示例.通常,正确分配值与实体,避免设置器,使用像Factory这样的模式创建对象和规范来验证复杂条件是有价值的技术,可以减少问题.这些技术可以消除许多基本问题.但至于如何处理复杂的验证案例,没有一个答案. (3认同)
  • 最后的评论。不要太关注技术细节。“严格按照书本”做 DDD 很困难,需要经验才能真正尝试。我参与的第一个 DDD 项目是在想法变得重要之前。我们有埃文斯过去,经验有限,当时几乎没有其他指导。我们没有区分值对象和实体对象,聚合被认为是设计中的概念,而不是在代码中强制执行。DDD 纯粹主义者会称之为废话,但我们编写了很好的代码并且应用程序受益。当您获得更多经验时,您可以改进您的技术。 (2认同)