N 层开发中的 DDD 概念
-
22-09-2019 - |
题
在花了几个月的时间研究 DDD 方法之后,我现在开始将这些概念应用到我公司的实际产品中。事实上,我的任务是为未来的开发创建一个合适且可维护的架构。
我们决定使用以下技术:EF4(真正的 v2)、Unity
我获得的信息量非常有启发性,但是,我在最佳实践中仍然存在几个问题:
问题#1: DTO - 最佳实践
我有我的域对象(POCO 类)。有多种方法可以实现这些类。
- 传统方法:创建包含公共 getter/setter、验证和适当业务逻辑的 POCO 类。还可以创建 DTO 并使用映射技术来管理它们。(自动映射器)
- 传统 - DTO:如上所述创建 POCO 类,但是使用 POCO 作为传输对象。据我了解,业务对象永远不应该离开域。
- 杂交种:我偶然发现了一个有趣的 博客文章 作者在其中创建了 POCO 对象和 DTO。他在域对象内部创建了一个 DTO 实例。这使得可维护性更容易,因为您不需要像#1 那样复制属性。就像这样:
public abstract class POCOBase<T> : ValidationBase, IPOCO where T : DTOBase, new() { public T Data { get; set; } public POCOBase() { Data = new T(); } public POCOBase(T dto) { Data = dto; } } public class SomePOCO : POCOBase { } public class SomeDTO : DTOBase { public String Name { get; set; } public String Description { get; set; } public Boolean IsEnabled { get; set; } } // EXAMPLES // POCOBase<SomeDTO> somePOCO = new SomePOCO(); // somePOCO.Data.Name = "blablabla"; // somePOCO.Validate(); // return somePOCO.Data;
问题2: UI/服务层应返回哪些对象?
这就是 DTO 的全部要点。一个非常简单的轻量级对象,仅包含裸属性。它也不包含任何验证结果。如果我将 DTO 序列化回客户端,则应该假设客户端需要任何验证结果,例如 InvalidRules 集合。
例如,假设我正在使用亚马逊的 API。我想将一本书添加到我的个人商店。如果我尝试添加一本书而不发送其 ISBN,该服务可能会返回某种包含验证结果错误的响应组。
我错过了什么吗?我的印象(至少来自 DDD“纯粹主义者”)DTO 不应该包含业务逻辑。在我看来,DTO 没有提供足够的信息作为传输对象。要么我需要一个新类型的 Response 对象来封装 DTO 和验证结果。
问题#3: 多少 IoC 太多了?
对我来说,显然我应该遵循黄金法则:
“确定应用程序的各个部分,并与保持不变的部分分开。”
对我来说,这对于应用 IoC 来说是有意义的。为了减少依赖性,我的表示层、业务逻辑层和数据访问层都通过 IoC 容器进行通信。我的应用程序层包含通用接口和抽象。比这更多地使用 IoC 似乎有些过分了。我喜欢这样一个事实:我可以创建模拟测试存储库,并且只需更改 Unity 的配置,我就可以利用 TDD。
我希望我已经清楚地表达了这些问题。提前感谢您的帮助!
解决方案
我将尝试一次解决您的一个问题。
答案1
DTO 与 DDD 是正交的,因为它们在应用程序体系结构中的不同位置服务于不同的目的。也就是说,DTO 在领域模型中没有地位,因为它们没有行为,因此会导致 贫血领域模型.
具有 Persistence Ignorance 的 POCO 是正确的选择。杰里米·米勒有一个很好的 解释这个概念的文章.
答案2
位于域模型之上的层通常需要返回自己的对象,这些对象是为相关目的而定制的。
对于 UI,MVVM 模式效果特别好。 本文 为 WPF 引入了 MVVM,但该模式在 ASP.NET MVC 中也有魅力。
对于 Web 服务,这就是 DTO 模式适用的地方。如果您想知道的话,WCF 数据契约是 DTO:)
这将需要在服务接口和领域模型之间来回进行大量映射,但这就是您必须为 Supple Design 付出的代价。你可能会发现 自动映射器 在这方面有帮助。
答案3
IoC 越多(实际上:DI)更好,但是关于你的问题的一件事让我印象深刻:DI 容器应该只连接对象图,然后就让开。对象不应依赖 DI 容器。
看 这个答案 更多细节。