Questions tagged «domain-driven-design»

域驱动设计(DDD)是一种通过将实现与不断发展的模型连接来开发满足复杂需求的软件的方法。

2
DDD-聚集大量子节点的根
首先,我会说我对DDD相对陌生,所以在这里我可能会犯一些基本错误! 我从事的项目涉及会计和交易(从财务角度而言)的概念。一个帐户可以针对它输入许多交易。 在我看来,“帐户”和“交易”都是实体,并且“帐户”是包含交易的汇总根,因为没有该帐户就无法存在“交易”。 但是,当我将其应用到代码中时,我立即遇到了问题。在许多情况下,始终拥有帐户中每个交易的列表对我来说并不是特别有用。我对能够执行诸如计算帐户余额和强制执行不变性(例如信用额度)之类的操作感兴趣,但是我也希望能够轻松处理一部分交易(例如,显示日期范围内的交易)。 在后一种情况下,如果我使用,则TransactionRepository可以有效地访问所需的那些对象,而无需加载整个列表(可能非常大)。但是,这将允许除帐户以外的其他事物与事务一起使用,这意味着我已经破坏了帐户作为聚合根的概念。 人们如何处理这种情况?您是否只接受为聚合根加载潜在大量子代所带来的内存和性能影响?

2
要存储库还是不存储库
当我第一次了解域驱动设计时,我还被介绍到了存储库和工作单元模式,这些存储模式和工作单元曾经看起来像是那些酷炫的孩子向数据库发送SQL查询(例如穴居人)的最佳选择。我对这个话题的了解越深,我越了解到它们似乎不再是必需的了,因为EF和NHibernate之类的ORM将工作单元和存储库都实现到一个称为会话或上下文的API中。 现在我不确定该怎么办。是否存储库。我真的很理解这样的论点,即这样的泄漏抽象只会使事情复杂化,而绝对没有增加任何可以简化数据访问的内容,但是,将我的应用程序的各个方面都耦合到例如Entity Framework的感觉并不正确。通常,我遵循一些简单的准则: 域层是系统的核心,包含实体,服务,存储库... 基础结构层提供基础结构领域的域接口的实现,例如文件,数据库,协议。 应用程序层承载一个组合根,该根将所有事物连接起来并进行编排。 我的解决方案通常如下所示: Domain.Module1 Domain.Module2 IModule2Repo IModule2Service Module2 Infrastructure.Persistence Repositories EntityFrameworkRepositoryBase MyApp Boostrapper -> inject EntityFrameworkRepositoryBase into IRepository etc. 我使用a保持域层整洁,IRepository<'T>这也是一个域问题,不依赖于任何其他告诉我如何访问数据的内容。当我现在要实现IModule2Service需要数据访问的具体实现时,我将不得不注入DbContext并将其直接耦合到基础架构层。(要进入Visual Studio项目,由于循环依赖关系,最终可能会非常棘手!) 另外有什么可以到其他托管和作品fucktons?CQRS?如何抽象一个纯粹的基础架构?


1
ORM POCO是否取代域实体?
这有点类似于这个问题,但是范围更广。 总的来说,有了像EF 4.1这样的POM支持的ORM,现在将您的域实体作为持久化到数据库的对象有意义吗? 借助EF 4或Linq-to-SQL等较旧的ORM,您的“数据库对象”是自动生成的,并与数据库紧密耦合,因此,对于非平凡的应用程序,先将它们映射到更健壮的智能域实体投入工作。 使用较新的ORM的想法是仅构建健壮的域实体,然后具有仅提供所述域实体与您的DBMS之间映射的数据层吗? 在写作中,我感觉到这一直是目标,但使用现有工具并不容易(轻松),至少在.NET世界中并非如此。

1
如何将DDD的某些概念应用于实际代码?里面的具体问题
我一直在研究DDD,目前正在努力寻找一种在实际代码中应用这些概念的方法。我在N层有大约10年的经验,所以我苦苦挣扎的原因很可能是我的思维模型与该设计太过相关。 我创建了一个Asp.NET Web应用程序,并从一个简单的域开始:Web监视应用程序。要求: 用户必须能够注册一个新的Web App进行监视。该Web应用程序具有友好的名称并指向URL。 该网络应用将定期轮询状态(在线/离线); 该Web应用程序将定期轮询其当前版本(该Web应用程序应具有“ /version.html”,这是一个在特定标记中声明其系统版本的文件)。 我的疑虑主要涉及责任分工,为每件事情找到适当的位置(验证,业务规则等)。在下面,我编写了一些代码,并添加了有关问题和注意事项的注释。 请批评指教。提前致谢! 领域模型 旨在封装所有业务规则。 // Encapsulates logic for creating and validating Url's. // Based on "Unbreakable Domain Models", YouTube talk from Mathias Verraes // See https://youtu.be/ZJ63ltuwMaE public class Url: ValueObject { private System.Uri _uri; public string Url => _uri.ToString(); public Url(string url) …

4
在复杂的以域为中心的应用程序中,用于基本CRUD操作的DDD方法
我的公司正在从头开始重写我们的Web应用程序。它是大型企业级应用程序,在金融行业中具有复杂的领域。 我们使用ORM(实体框架)进行持久化。 本质上,我们的应用程序的一半集中在从用户那里收集原始数据,进行存储,然后包含大部分实际域逻辑的应用程序的另一半使用原始数据来创建我们的域图片,该域图片与原始数据有很大的不同原始输入,并将其传递到calc引擎,运行calcs,并吐出结果,然后将结果显示给用户。 在使用层的DDD方法中,CRUD操作似乎遍历域层。但至少在我们看来,这似乎没有道理。 例如,当用户转到编辑屏幕以更改投资帐户时,屏幕上的字段是存储在数据库中的确切字段,而不是以后用于计算的域表示形式。那么,当编辑屏幕需要数据库表示形式(原始输入)时,为什么要加载投资帐户的域表示形式呢? 在用户单击投资帐户屏幕上的“完成”,并对控制器执行POST之后,控制器现在几乎具有需要保存的投资帐户的确切数据库表示形式。但是出于某种原因,我应该加载域表示以进行修改,而不是仅将控制器模型直接映射到数据库模型(实体框架模型)? 因此,从本质上讲,我是将数据模型映射到域模型,以便可以将其映射回数据模型以持久化。这有什么意义?

3
API对象定义包含第三方引用ID作为属性是否不好?
像这样: Campaign: type: object properties: id: type: string description: "A GUID identifier" referenceId: type: string description: "A consumers identifier they have used to map their own systems logic to this object." name: type: string description: "'Great Campaign 2017' as an example" 我担心referenceId。 系统域是一个平台,该平台通过数据导出和各种格式(xml,excel)的导入以多种方式与第三方集成。它已经足够成熟,可以允许第三方通过API与我们的系统集成,而该API的设计正是引发这一问题的原因。 我们有一个名为Campaign的对象,该对象的ID可用于识别和检索资源。我们API的消费者可能在自己的域内拥有自己的参考代码,以作为他们认为是广告系列的参考代码。 我们系统中还有其他带有第三方参考字段的对象,这是我们现有消费者所期望的。但是我担心这给我们增加了映射的负担,我们不知道这个referenceId是什么(数字,文本,json?),并且为新使用者增加了另一个令人困惑的属性。 在API的公共对象定义中允许第三方引用ID字段被视为不良做法或不良设计?

4
如何清楚定义边界上下文的边界
经过一个月左右的阅读和研究DDD,我决定开始自己的项目,并使用这些有限的上下文创建DDD。 客户群 产品展示 命令 开票 每个有界上下文都有其余的API作为表示层,域层,持久层。 到目前为止,代码运行顺利,但是来自一个单一的世界,我仍在尝试找出以下内容: 当我想创建一个新客户时,发出新发票,创建我想要的新订单,例如访问国家列表。我要: a)在每个卑诗省创建一个国家列表 b)创建一个国家BC-> API并使用它来获取可用国家的列表 c)使用第三方API并通过每个BC中的反腐败层提取数据 当使用反腐败层或适配器层与第三方API集成时,我的域模型中必须包含哪些数据?例如,如果我想将zendesk API与Client BC集成在一起。我是否仅需要我域中的ticketID,还是必须从Zendesk中提取要在Client BC中访问和使用的所有数据? 如果我的MVC应用程序实际上是从API(我的受限上下文的表示层)获取数据的,那么我很难清楚地定义每个BC的边界。这是否意味着经过适当设计的BC可以为单个MVC控制器提供服务,而无需使用其他API?


4
用DDD(或有意义)建立模型关系?
这是一个简化的要求: 用户创建一个Question带有多个Answer的。Question必须至少有一个Answer。 澄清:思考Question并Answer像测试一样:有一个问题,但是有几个答案,其中几个可能是正确的。用户是准备此测试的演员,因此他创建了问题和答案。 我正在尝试对这个简单的示例进行建模,以便1)匹配现实生活模型2)用代码进行表达,从而最大程度地减少潜在的误用和错误,并向开发人员提示如何使用该模型。 问题是实体,答案是价值对象。问题包含答案。到目前为止,我已经有了这些可能的解决方案。 [A]工厂内Question 除了Answer手动创建,我们可以调用: Answer answer = question.createAnswer() answer.setText(""); ... 这将创建一个答案并将其添加到问题中。然后,我们可以通过设置其属性来操纵答案。这样,只有问题才能创造答案。此外,我们会避免没有问题的答案。但是,我们无法控制创建答案的方式,因为答案已在中进行了硬编码Question。 上述代码的“语言”也存在一个问题。用户是创建答案而不是问题的人。就我个人而言,我不喜欢我们创建值对象并依靠开发人员将其填充值-他如何确定需要添加什么? [B]工厂内部问题,参加#2 有人说我们应该在以下方法中使用这种方法Question: question.addAnswer(String answer, boolean correct, int level....); 与上述解决方案类似,此方法将强制性数据用于答案并创建一个也将添加到问题中的答案。 这里的问题是我们无缘无故地复制的构造函数Answer。另外,问题真的会产生答案吗? [C]构造函数依赖 让我们自由地自己创建两个对象。我们还要在构造函数中表达依赖权: Question q = new Question(...); Answer a = new Answer(q, ...); // answer can't exist without a question 这为开发人员提供了提示,因为不能毫无疑问地创建答案。但是,我们看不到“语言”表明答案已“添加”到问题。另一方面,我们真的需要看到它吗? [D]构造函数依赖项,采用#2 我们可以做相反的事情: Answer a1 …

2
DDD:不可变的对象也可以是实体吗?
我已经阅读了无数关于实体和值对象之间差异的文章,尽管我确实认为至少在概念上我理解两者之间的区别,但似乎在其中一些文章中,作者认为特定领域概念是一个VO,仅仅是因为它是不可变的(因此,其状态将永远不会改变,至少在该特定域模型内)。 您是否同意,如果某个对象的状态在特定的域模型内永远不会改变,那么该对象永远不应是一个实体?为什么?

4
确保交易与DDD的一致性
我从DDD开始,并了解使用聚合根来确保跨国一致性。我们不应在一项应用程序服务中修改多个聚合。 但是,我想知道如何处理以下情况。 我有一个称为“产品”的聚合根。 还有一个称为“组”的聚合根。 两者都有ID,并且可以独立编辑。 多个产品可以指向同一组。 我有一个可以更改产品组的应用程序服务: ProductService.ChangeProductGroup(string productId, string groupId) 检查组存在 从仓库获取产品 设置组 将产品写回到存储库 我还有一个可以删除组的应用程序服务: GroupService.DeleteGroup(string groupId) 1.从其groupId设置为提供的groupId的存储库中获取产品,确保计数为0或中止2.从组存储库中删除组3.保存更改 我的问题是以下情况,如果发生以下情况: 在ProductService.ChangeProductGroup中,我们检查该组是否存在(确实存在),然后在此检查之后,一个单独的用户(通过另一个GroupService.DeleteGroup)删除了productGroup。在这种情况下,我们为刚刚删除的产品设置了参考? 这是我设计中的缺陷吗?我应该使用其他域设计(如有必要,添加其他元素),还是必须使用事务处理?

2
在执行DDD时是否应该模拟实体和值对象?
阅读后几 文章约Newable VS 注射对象以及如何将这些概念涉及到DDD的服务,实体和值对象,我留下了有关使用我的代码newables尤其是在我的单元测试的一些疑虑。 可更新项的主要候选对象是Entities和Value对象,这意味着与其将这些依赖项注入其他对象中,还应该只是new这些对象的一个​​实例,并直接在代码中使用它们。 但是,良好的DDD做法主张将责任分配给实体和价值对象(如果认为合适的话)。因此,实体和价值对象将最终在其中包含一些严肃的业务逻辑。 现在,如果服务在实体或值对象上运行,我应该模拟该实体或值对象并将该模拟传递给该服务(模拟将要求interface对似乎被提倡的价值对象或实体使用)? 还是我应该只是new一个实体/值对象,并将具体实现传递给服务,从而违反仅测试一个单元的单元测试原理?

3
DDD中的Presentation VS Application层
我在域驱动设计中的表示层和应用程序层之间划清界限时遇到麻烦。 控制器,视图,布局,Javascript和CSS文件应该放在哪里? 是在应用程序层还是表示层中? 如果它们都放在同一层,那么包含另一层的是什么?是空的吗?

3
DDD和值对象。可变值对象是否适合使用非Aggr。根实体?
这是一个小问题 有一个带有值对象的实体。没问题 我将值对象替换为新值对象,然后nhibernate插入新值并孤立旧值,然后将其删除。好,那是个问题。 被保险人是我在我域中的实体。他有一组地址(值对象)。地址之一是MailingAddress。当我们要更新邮寄地址时,假设邮编是错误的,按照埃文斯先生的学说,我们必须将旧对象替换为新对象,因为它是不可变的(值对象对吗?)。 但是我们不想删除您的行,因为该地址的PK是MailingHistory表中的FK。因此,按照埃文斯先生的学说,我们在这里几乎陷入了困境。除非我将地址设为实体,否则就不必“替换”它,只需像过去的美好时光那样更新其邮政编码成员即可。 在这种情况下,您会建议我什么?从我的角度来看,ValueObjects仅在您希望封装一组数据库表的列(nhibernate中的组件)时才有用。最好在数据库中具有持久性ID的所有对象都设置为实体(不一定是聚合根),这样您就可以在不重新创建整个对象图的情况下更新其成员,特别是如果这是一个深层嵌套的对象。 你同意吗?埃文斯先生是否允许使用可变的价值对象?还是可变值对象是实体的候选对象? 谢谢

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.