领域驱动设计 - 各层应如何组织?
我对软件开发非常陌生。我认为分层架构是减少面向对象软件开发过程中出现的复杂性的好方法,更不用说保持代码的组织性了。
我有兴趣了解领域驱动设计方法,并且我遇到了一些问题来让自己了解它(当然,初学者级别的问题)。
就是这样 -
我想构建一个应用程序来将人员相关数据保存在数据库中,并在 WPF DataGrid
中显示人员详细信息(我知道,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
}
}
现在,我对 DDD 的理解表示架构(最简单的版本)应该如下所示(如果我错了,请纠正我)-
注意:
我希望将
DataGrid
绑定到某些 < code>ObservableCollection,立即反映任何类型的更改。这是一个 WPF 应用程序,但不一定采用 MVVM 模式,我故意想使用后面的代码。
我的问题是 -
什么类型的代码属于
应用层
?我的猜测是,我绝对不应该将域对象(即
Person
)的ObservableCollection
绑定为ItmsSource
的>数据网格。那么我应该从域对象中提取什么类型的对象,以及如何提取?为了保持
表示层
和域层
之间的解耦,可能有一个约定,例如永远不要直接在表示层中实例化域对象
。那么什么是非直接
方法呢?如果后台代码与
应用程序层
对话,那么应用程序层
是否应该与数据存储库
对话?但是,如果需要某种与数据访问无关的域访问(可能不在这个应用程序中,但它可能会发生,对吗?)怎么办?在这种情况下,那个X<
领域层
中的 /code> 家伙(子层/模块),应用层
应该与之通信?
我知道我的问题非常业余,但它们确实是问题,是从我面临的问题中提出的,目的是为了获得清晰的了解。因此,如果有人有时间,任何回复将不胜感激。
编辑:我不确定数据存储库
是否应该有域模型
的引用。
I'm very much new to software development. I think layered architecture is a great way to reduce the complexities that arise in the process of object oriented software development and, not to mention, to keep your code organized.
I'm interested to learn about Domain Driven Design approach and I've run into some problems to get myself introduced to it (of course, beginner level ones).
Here it is -
I want to build an application to save person related data in database and display person details in a WPF DataGrid
(I know, DDD is definitely not for the apps of such scale, but just to keep things simple for an amateur like me). So, I created a domain class "Person", something like –
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
}
}
Now, my understanding of DDD says the architecture (the simplest version of it) should be as follows (please, correct me if I'm wrong) -
Note:
I want the
DataGrid
to be bound to someObservableCollection
, to reflect any kind of changes instantly.It's a WPF application but not necessarily be in MVVM pattern and I deliberately want to use the code behind.
My questions are -
What kind of codes belong to the
Application Layer
?My guess is, I should definitely not bind an
ObservableColletion
of my domain object (i.e.Person
) as theItmsSource
of theDataGrid
. What type of object then I should extract from the domain object, and how?To keep a decoupling between
Presentation Layer
andDomain Layer
probably there's a convention likenever instantiate domain objects directly in the presentation layer
. What are thenon-direct
approaches then?If the code-behind talks to the
Application Layer
then should theApplication Layer
talk to theData Repository
? But what if some kind of domain access is needed which is not data access related (may be not in this app, but it may occur, right?) In that scenario, who's thatX
guy (sub-layer/module) inDomain Layer
that theApplication Layer
should talk to?
I know my questions are of very much amateur level, but they are questions indeed, raised from problems I'm facing to get a clear picture. So, if anybody has time, any response will be appreciated.
EDIT : I'm not sure if Data Repository
should have a reference of Domain Model
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
就更“经典”的 DDD 而言,域对象通常不允许在域之外的任何地方。但表示层不使用领域对象并不是绝对的规则。例如,Naked Objects 代表了直接使用领域对象的思想流派。我自己主要坚持不直接使用域对象的哲学,所以我不熟悉他们建议的所有实践,我个人认为直接绑定到域对象是不明智的,但是......只是保持在请注意,并非每个人都认为这是一个要求。
如果不允许域对象位于域本身之外,则通常会使用 DTO 或数据传输对象,它们只是仅具有属性的类,并且此类 DTO 类没有域行为。 DTO 通常准确地反映领域模型结构,但并非必须如此。
业务逻辑应该在域模型中实现,因此应用程序层中的大部分内容都涉及协调各种服务,通常是将数据传入和传出客户端应用程序。许多人为此使用某种形式的 SOA 或至少 Web 服务。它们调用存储库,但还需要其他组件(例如汇编器)来获取从存储库调用返回的域对象,并将属性值复制到 DTO 中,然后将其序列化并返回给调用者。调用者通常是演示者或控制器,但如果您不使用 MVC 或 MVP,调用者仍将位于表示层。反向行程更复杂 - UI 可能会发回代表更新的 DTO 或代表要添加的新对象的 DTO。应用程序层的主要目的是协调这些来回活动。
至于领域层的“非数据访问”,有几个典型的例子。大多数人通常将您可能认为是域服务的“X”组件称为域服务。领域服务与应用程序服务的不同之处在于它更接近领域模型并且存在实际业务逻辑。
例如,如果一个应用程序涉及某种订单下达,那么实际上有两个问题——订单下达和订单履行。应用程序服务将制定订单放置所需的数据传输到 UI,然后返回用户希望放置的订单。但这只是中介数据传输,这就是应用程序服务的终点。然后可能需要域服务来应用业务规则并构建实际履行该订单所需的其他域对象。
总的来说,我发现这是一个有用的概念或隐喻,可以应用于许多场景 - 应用程序服务仅就请求提交而言促进某种类型的请求。另一方面,域服务有助于满足实际的请求。
除了面向数据之外,我遇到过或可以轻易想象到的唯一其他“访问”模式是面向过程的功能。这种情况并非在每个应用程序中都会遇到,但在某些领域很普遍。例如,在我工作的医疗保健领域,您可能需要包含管理临床数据和临床流程的重要元素的应用程序。我通过不将该过程重点作为我的领域模型的一部分并使用不同的工具来解决这个问题。
OOP 技术不太适合实际流程本身,但它们对于向流程提供数据和从流程捕获数据很有用。毕竟,面向对象首先也是面向名词的。对于实时流程管理,您需要“面向动词的编程”而不是“面向名词的编程”。工作流工具是“面向动词”的工具,可以补充数据密集型和流程密集型应用程序的领域驱动模型。我做了很多涉及 C# DDD 模型和 Workflow Foundation 模型的工作,但同样,这仅适用于某些类型的应用程序。许多典型的业务应用程序只需要域模型和服务。
最后,DDD 最重要的方面不是任何技术或架构。它的真正核心围绕着无处不在的语言以及与领域专家的互动(我强烈认为是直接互动),以提炼出关键的领域知识。 (我认为大多数声称做DDD的公司并不是因为那么多公司拒绝让业务和开发直接交互,但那是另一个话题了……)它是领域知识的提取和融合,而不是任何实际上将 DDD 与传统 OOP 区分开来的技术,这就是 DDD 的真正价值所在。
编辑
就存储库使用而言,该图是正确的。通常,应用程序层总是通过域对象的存储库。首先,您必须能够将数据带入应用程序,并且大多数应用程序还需要一定程度的查询能力。
域层 OTOH 通常不与存储库交互。通常,您希望领域模型是独立的并且与任何特定技术分离,即它应该代表“纯领域知识”。持久性本质上与某种特定技术紧密耦合,因此一般来说,人们努力使他们的领域模型摆脱任何持久性实现。您有存储库,但通常不想在域模型中调用存储库方法。
在域模型本身内,对象可以作为新对象(可以直接实例化或通过工厂实例化)获得,也可以通过遍历关联来获取。有时,在创建新对象时,将所需的所有内容传递到构造函数中是不切实际的,因此在这种情况下,您可能需要在域模型本身内进行某种数据访问。通常人们所做的就是通过接口传入数据服务,以便为领域模型提供数据访问,但与数据层实现保持解耦。但在大多数情况下,领域对象会与已实例化的其他领域对象进行操作和交互。
Speaking in terms of more "classical" DDD, yes domain objects are typically not allowed anywhere outside of the domain. But it is not an absolute rule that domain objects are not used in the presentation layer. For example, Naked Objects represents a school of thought where domain objects are used directly. I myself adhere mostly to a philosophy where domain objects are not used directly, so I am not familiar with all the practices they suggest, I personally would think binding to a domain object directly would be ill-advised, but ... Just keep in mind not everyone views this as a requirement.
If you do not allow domain objects outside of the domain itself, you would typically use DTO or Data Transfer Objects which are simply classes only with properties and such DTO classes do not have domain behaviors. DTOs often mirror the domain model structure exactly but do not have to.
Business logic is supposed to be implemented in the domain model, so much of what is in the application layer is involved with coordinating various services, typically to bring the data to and from the client applications. Many people use some form of SOA or at least web services for this. These call the repositories but also require other components such as assemblers to take the domain objects returned from repository calls and copy the property values into DTOs, which are then serializable and returned to the caller. The caller is often a presenter or controller but if you are not using MVC or MVP the caller would still be in the presentation layer. The reverse trip is more complex - the UI may send back DTOs that represent updates or DTOs that represent new objects to be added. The prime purpose of the application layer is mediating these back and forth activities.
As far as "non-data access" of the domain layer, there are a couple of typical examples. Most people usually refer to the "X" component you may be thinking of as a Domain Service. A Domain service differs from an Application Service by it's proximity to the domain model and the presence of actual business logic.
For example, if an application involves some kind of order placement, there are actually two concerns - order placement and order fulfillment. Application Services mediate the transfer of the data needed to formulate an order placement to the UI and then return the order that the user wishes to place. But that is only mediating data transfer and that is where Application Services end. A Domain Service may then be needed to apply business rules and construct additional domain objects that are needed to actually fulfill that order.
In general, I find that to be a useful concept or metaphor that can be applied to many scenarios - an Application Service facilitates a request of some sort, in terms of the request submission only. A Domain Service on the other hand facilitates the actual request fulfillment.
The only other mode of "access" other than data-oriented I have encountered or can readily imagine is process-oriented functionality. This is not encountered in every application but is prevalent in certain fields. For example in healthcare where I work you may want applications that incorporate significant elements of managing both the clinical data as well as the clinical process. I solve this problem by not making that process emphasis a part of my domain model and using different tools for that instead.
OOP techniques are not well suited for an actual process itself, they are useful for providing data to and capturing data from a process. Object-oriented is after all also primarily noun-oriented. For real-time process management you need "verb oriented programming" more than "noun oriented programming". Workflow tools are "verb oriented" tools that can be complementary to Domain-driven models for applications that are both data-intensive and process-intensive. I do a lot of work that involves both C# DDD models and Workflow Foundation models, but again this is only needed for certain types of applications. Many typical business apps only require domain models and services.
Finally the most important aspect of DDD is not any technique or architecture. The real heart of it revolves around the Ubiquitous Language and interaction with (in my strong opinion DIRECT interaction with) domain experts to distill out critical domain knowledge. (Most companies that claim to do DDD in my opinion do not because so many companies refuse to allow the business and development to interact directly, but that is another topic... ) It is the extractions and incorporation of domain knowledge, rather than any technique that actually separates DDD from conventional OOP and that is where the real value of DDD arises.
EDIT
As far as repository use goes, the diagram is correct. Typically the application layer always goes through a repository for domain objects. First of all, you have to be able to bring data to the application, and most applications also need some level of query ability.
The domain layer OTOH usually does not interact with repositories. Typically you want the domain model to be self-contained and decoupled from any specific technology, i.e it should represent "pure domain knowledge". Persistence is inherently tightly coupled to some sort of specific technology, so in general, people strive to make their domain models free of any persistence implementation. You have repositories but you typically do not want to call repository methods in the domain model.
Within the domain model itself, objects are obtained either as new objects (which may be instantiated directly or through a factory) or else reached by traversing associations. Sometimes when creating a new object it is impractical to pass everything needed into a constructor, so this is one case where you might need some sort of data access within the domain model itself. Usually what people do is pass in a data service via an interface so that the domain model may be provided with data access but remains decoupled from the data layer implementation. But for the most part, domain objects act and interact with other domain objects that are already instantiated.