29

我在软件开发方面非常新颖。就我个人而言,我认为分层体系结构是减少面向对象方法在软件开发过程中产生的复杂性的一种好方法,更不用说保持代码的组织性。现在,我遇到了DDD(域驱动设计)引入的一些问题。当然,初学者水平。
这里是 -
假设我想构建一个应用程序来保存数据库中的“人员”相关数据,并在wpf数据网格中显示个人详细信息(DDD绝对不适用于这种规模的应用程序,而只是为了保持对于像我这样的业余爱好者来说很简单)。所以,我设计了一个域类“人”,有点像 -DDD:应该如何组织图层?

public class Person 
{ 
    public Person(dataType paramA, dataType paramB) 
    { 
     _fieldA = paramA; 
     _fieldB = paramB; 
    } 

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

    private dataType _fieldB; 
    public dataType PropertyB 
    {   
     //encapsulates _fieldB  
    } 

    public dataType PropertyX 
    {   
     //some code based on private fields  
    } 

    public dataType PropertyY 
    {   
     //some code based on private fields  
    } 

    private dataType MethodPQR(dataType param) 
    {   
     //some code  
    } 

    public dataType MethodUVW(dataType paramOne, dataType paramTwo) 
    {   
     //some code  
    } 
} 

现在,我的DDD的理解说的架构(它的最简单的版本)应该是如下(请纠正我,如果我错误) -
enter image description here
注:

  1. 我想将DataGrid绑定到一些的ObservableCollection,只是即时反映任何样的变化。

  2. 这是一个WPF应用程序,但不一定是在MVVM模式,我故意要这样使用后面的代码(我也不知道,如果自己后面的代码代表了应用层)

我问题是 -

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

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

  3. 为了保持表示层对象和域层对象之间的解耦,可能会出现像“never instantiate domain objects directly in presentation layer”这样的约定。那么什么是非直接的方法?

  4. 如果Code-Behind与应用层对话,那么应用层是否应该与Repository进行通信?但是,如果需要某种类型的域访问,而不是而不是数据访问相关(可能不在此应用中,但可能会发生,对吗?)谁是应用层应该与之通信的域层中的X人?

我知道我所有的问题和问题都非常非常业余水平。但他们确实是问题和问题。所以,如果有人有时间,任何回应将不胜感激。

编辑:我不确定数据存储库是否应该有一个域模型的参考。

回答

32

就更多的“经典”DDD而言,yes域对象通常不允许在域以外的任何地方使用。但是,在表示层中不使用域对象是绝对的规则。例如,裸体对象代表了直接使用域对象的学派。我自己主要是坚持域对象不直接使用的哲学,所以我不熟悉他们所建议的所有做法,我个人会认为直接绑定到域对象会被建议,但是......请记住并不是每个人都认为这是一个要求。

如果你不允许域本身之外的领域对象,你通常使用的是没有域的行为简单的属性只有类DTO或数据传输对象。 DTO经常反映域模型结构,但不一定。

业务逻辑应该在领域模型中实现,那么多的东西是在应用层是参与协调各种服务,通常带来的数据和从客户端应用程序。许多人为此使用某种形式的SOA或至少Web服务。这些调用存储库,但也要求其他组件(如汇编程序)从存储库调用中返回域对象,并将属性值复制到DTO中,然后将其序列化并返回给调用者。调用者通常是演示者或控制器,但如果您未使用MVC或MVP,调用者仍将处于表示层中。反向行程更复杂 - 用户界面可能会发回表示更新的DTO或表示要添加的新对象的DTO。调解这些来回活动主要是应用程序层的目的。

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

例如,如果一个应用程序涉及到某种顺序放置的,其实有两个问题 - 下订单和订单履行。应用程序服务调解将订单放置到UI中所需的数据传输,然后返回用户希望放置的订单。但这只是调解数据传输,这就是应用程序服务结束的地方。然后可能需要域服务来应用业务规则并构建实际完成该订单所需的额外域对象。

一般来说,我发现这是一个有用的概念或隐喻,可以应用于许多场景 - 应用服务仅根据请求提交方便某种请求。另一方面,域服务便于实际请求履行

“获取”唯一的其他模式以外面向数据我所遇到的或可容易地想象是面向过程的功能。这在每个应用程序中都没有遇到,但在某些领域普遍存在。例如,在我工作的医疗保健领域,您可能需要包含管理临床数据和临床过程的重要元素的应用程序。我解决这个问题的方式不是将该流程强调作为我的领域模型的一部分,而是使用不同的工具。

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

最后,DDD最重要的方面不是任何技术或体系结构。它的真正核心是围绕无处不在的语言和与领域专家之间的互动(在我强烈的意见DIRECT互动中)来提炼关键领域知识。 (在我看来,大多数声称做DDD的公司并不是因为这么多公司拒绝让业务和开发直接互动,而是另一个话题......)这是领域知识的提取和合并,而不是任何这种技术实际上将DDD从传统的OOP中分离出来,这就是DDD的实际价值所在。

编辑

由于作为仓库使用走得远,该图是正确的。通常,应用程序层始终通过域对象的存储库。首先,您必须能够将数据带入应用程序,并且大多数应用程序也需要一定程度的查询能力。

域OTOH通常做而不是与存储库交互。通常情况下,您希望域模型与任何特定技术自成一体并解耦,即它应该表示“纯领域知识”。持久性本质上与某种特定技术密切相关,所以通常人们会努力使自己的领域模型不受任何持久性实现的影响。您有存储库,但通常不想在域模型中调用存储库方法。

在域模型本身中,对象可以作为新对象(可以直接实例化或通过工厂实例化)获得,也可以通过遍历关联达到。有时,在创建新对象时,将所需的所有内容都传递给构造函数是不切实际的,因此,您可能需要在域模型本身中进行某种数据访问。通常人们所做的是通过接口传递数据服务,这样域模型可以提供数据访问,但仍与数据层实现解耦。但是大部分域对象都起作用并与已经实例化的其他域对象进行交互。

+0

@Sisyphus:现在+1,清洁和详细的描述,以及你的时间来开导我。但是,更多的问题会来到你的方式:) – atiyar 2011-05-06 18:09:11

+0

@Sisyphus:再次感谢。你的建议很整洁,应用程序服务和域服务之间的区别非常有帮助。还有一个问题。应用层是否可以直接访问存储库,或者它总是通过域层?我的意思是,几乎总是,每个请求**履行**执行某种域限制(验证可能)检查任何请求**提交**,对不对?那么应用层不应该向域层提交每个请求,只有域层可以访问存储库? – atiyar 2011-05-07 20:07:45

+1

因为意见是有限的,我添加到我的答案。见编辑部分。 – Sisyphus 2011-05-08 10:51:27