首页 / 软件开发 / .NET编程技术 / 领域驱动设计的编码: 数据聚焦型开发的技巧
领域驱动设计的编码: 数据聚焦型开发的技巧2014-03-10 MSDN Julie Lerman今年,Eric Evans 具有开创性的软件设计图书“Domain-Driven Design: Tackling Complexity in the Heart of Software”(领域驱动设计:软件核心复杂性应对之道) (Addison-Wesley Professional,2003 年,amzn.to/ffL1k)迎来了其出版十周年的纪念日。Evans 在本书中分享了其指导大型企业完成构建软件的过程的多年经验。他随后花了更长时间考虑 如何概括帮助这些项目获得成功的模式 - 与客户交互、分析要解决的企业问题、组建团队和 设计软件的架构。这些模式的焦点是企业的领域,它们共同组成领域驱动设计 (DDD)。利用 DDD,您可以为有问题的领域建模。这些模式是通过抽象化您对领域的知识产生的。即使在今 天,重读 Martin Fowler 的前言和 Evans 的序言仍能获得对 DDD 本质的丰富概览。在本专栏以及接下来的两个专栏中,我将分享一些指导原则,在我着手让我的代码从 某些 DDD 技术模式获益时,这些原则帮助我那注重数据的 Entity Framework 大脑保持清晰 的思维。我为什么关注 DDD?我对 DDD 的介绍摘自发布于 InfoQ.com 上的对 Jimmy Nilsson 的简短视频访谈。Jimmy Nilsson 是 .NET 社区(以及其他地方)一位受人尊敬的架构师,他在访谈中谈到了 LINQ to SQL 和 Entity Framework (bit.ly/11DdZue)。在访谈的最后,Nilsson 被要求列 举他最喜欢的技术书籍。他回答道: “我最喜欢的计算机书籍是 Eric Evans 编著的 “Domain-Driven Design”(领域驱动设计)。我觉得它就像诗一样美妙。它不仅内容精彩 ,还有诗一般的韵味,让人百读不厌。”诗一般的美妙!当时,我正在写我的第一本技术书 籍“Programming Entity Framework”(实体框架编程)(O’Reilly Media,2009 年), 这一描述引发了我的兴趣。因此,我去读了一点 Evans 的书,想看看到底写得如何。Evans 是一个行文优美而流畅的作者,再加上他在软件开发领域具有敏锐而自然的见解,读者在阅 读本书时体验到了充分的乐趣。不过,使我感到震撼的还有我读到的内容。Evans 不仅文笔 极佳,而且书中的内容也非常吸引我。他提到与客户建立关系并真正了解其业务和业务问题 (与有问题的软件有关),而不只是苦苦编写代码。在我 25 年的软件开发生涯中,这个观 点起到了举足轻重的作用。我想要实现更多。我在 DDD 领域的边缘又徘徊了很多年 ,然后开始了解更多内容 - 我在一次会议上见到了 Evans,随后参加了他为期四天的浸入式 研讨会。虽然我远远不是 DDD 方面的专家,但我发现在试图将自己的软件创建过程向更有条 理且更易于管理的结构转变时,可立即使用“界定的上下文”模式。您可以阅读我的 2013 年 1 月专栏中的主题“使用 DDD 界定的上下文收缩 EF 模型”(msdn.microsoft.com/magazine/jj 883952)。从那时起,我对 DDD 的研究又深入了一步。我对 DDD 感到深深着迷 ,并从中获得了很多灵感,但我为从数据驱动的角度理解一些可推动成功的技术模式而纠结 。似乎有很多开发人员也遇到了相同的问题,因此我想分享在 Evans 和很多其他 DDD 实践 者和教师(包括 Paul Rayner、Vaughn Vernon、Greg Young、Cesar de la Torre 和 Yves Reynhout)的慷慨帮助和关心之下吸取的经验教训。在为域建模时忘记持久性为域建模就是重点关注企业的任务。在设计类型及其属性和行为时,我非常倾向于 考虑关系如何在数据库中发挥作用以及我选择的对象关系映射 (ORM) 框架(即 Entity Framework)将如何处理我构建的属性、关系和继承层次结构。除非您为从事数据存储和检索 业务的公司(像 Dropbox 一样)构建软件,否则数据持久性仅在您的应用程序中起到支持作 用。这非常像调用天气源的 API 以便向用户显示当前温度,或者,从您的应用程序向外部服 务发送数据(可能是 Meetup.com 上的注册信息)。当然,您的数据可能更加复杂,但利用 DDD 的上下文界定方法,通过关注行为和在构建类型时遵循 DDD 指导,持久性可能比您在今 天构建的系统简单得多。如果您已仔细研究 ORM(例如,了解如何使用 Entity Framework Fluent API 配置数据库映射),则应能根据需要实现持久性。最糟糕的情况是, 您可能需要对您的类做一些调整。在极端情况下(例如,使用旧数据库时),您甚至可以添 加专为数据库映射设计的持久性模型,然后使用 AutoMapper 等工具解析域模型和持久性模 型之间的映射。但是,这些关注点与您的软件用于解决的业务问题无关,因此持久性 不应影响域设计。这对我来说是一个难题,因为我在设计实体时会忍不住考虑 EF 将如何推 断其数据库映射。因此,我试图解决这件烦心事。私有 Setter 和公共方法另一个经验法则是将属性 setter 设为私有。您应使用修改属性的方法控制与 DDD 对象及其相关数据的交互,而不是允许通过调用代码来随机设置各种属性。不,我不是指 SetFirstName 和 SetLastName 之类的方法。例如,您在创建新客户前需要考虑一些规则, 而不是实例化新的 Customer 类型并设置其各个属性。您可以将这些规则内置于 Customer 的构造函数中,使用 Factory Pattern 方法,甚至在 Customer 类型中包含 Create 方法。 图 1 显示按照聚合根(即对象图的“父级”,也称为 DDD 中的“根实体”)的 DDD 模式定 义的 Customer 类型。客户属性具有私有 setter,以便仅 Customer 类的其他成员能够直接 影响这些属性。该类公开了构造函数以控制其实例化方式,并将无参数构造函数(Entity Framework 需要)隐藏为内部构造函数。