使用 C# 清洁架构:在值对象中执行验证的更好设计
Clean architecture with C#: A better design to perform validation in Value Objects
我正在创建一个应用程序,其架构是基于 Uncle Bob's Clean Architecture concepts and DDD。请注意,它是基于 DDD 的 BASED,所以我给了自己与严格 DDD 不同的自由。
为了创建此应用程序,我使用了 C# 和 .Net Standard 2.0
DDD 的原则之一与值对象有关。根据Wikipedia,值对象的定义如下:
Value Object
An object that contains attributes but has no conceptual identity. They should be treated as immutable.
Example: When people exchange business cards, they generally do not distinguish between each unique card; they only are concerned about the information printed on the card. In this context, business cards are value object
现在,我希望我的值对象在某些验证不成功时不允许创建它们。当它发生时,将在实例化过程中抛出异常。我真的打算在那里抛出一个异常,因为架构的核心确实不希望任何无效数据达到那个点。
在进一步讨论这个问题之前,为了给你们更多背景知识,here 是我的架构(注意:仍然不完整):
我在这个架构中遵循的规则是:
- 一个层只能知道它的最内层邻居层的接口
- 一个层无法知道任何最外层的信息
- 层之间的所有通信必须通过接口完成
- 每一层都必须可以独立部署
- 每一层都必须可以独立开发
为了更好地理解图中的箭头,我建议阅读那些 Stack Exchanges 的问题:
Explanation of the UML arrows
https://softwareengineering.stackexchange.com/questions/61376/aggregation-vs-composition
现在,我现在面临的挑战是找到一种使用验证器的好方法。在这一点上,我对我的架构不满意。问题如下:
因为我可以在给定时间实例化数千个值对象,所以我不希望值对象的每个实例都有一个实例方法来执行验证。我希望验证方法是静态的,因为它的逻辑对于每个实例都是相同的。另外,我希望架构的上层可以使用验证逻辑来执行验证,而无需尝试实例化值对象,从而导致抛出昂贵的异常。
问题是:C# 不允许静态方法的多态性,所以我不能做类似的事情:
internal interface IValueObject<T>
{
T Value { get; }
static bool IsValid(T value);
}
如何在不依赖静态方法多态性的情况下实现此功能,同时不浪费内存?
你可以抽象地思考是件好事,但你应该在编写了一些工作代码后进行概括。
一般干净的 on-size-fit-all 架构 DDD 是一个 Mith。实际上 DDD 只适用于 Domain 层。这就是它的美妙之处,它与技术无关。
在我的项目中,我什至没有基础 class 或值对象、实体或聚合根的接口。我不需要它们。所有这些积木都是 POPO (PHP)。
在我看来,干净的架构是使领域层技术不可知,不依赖于任何外部框架的架构。其他层几乎可以是任何东西。
我建议您摆脱 IsValid()
并创建您的值对象 self-checking、always valid 对象。建议使它们不可变,这显然会在这方面有很大帮助。您只需在创建过程中检查一次不变量。
[编辑]
您可能需要将其视为输入验证的第一遍而不是值对象不变强制。如果有大量不安全的数据进入,你想将其转化为值对象,首先在外层的验证过程中处理它——你可以进行所有你需要的性能优化,实现错误逻辑并协调 VO 创建。
在干净的架构中,所有业务逻辑都进入用例交互器。验证规则是业务逻辑的一部分,因此也应该进入用例交互器。
在你的情况下,我建议将你的验证放在采用 "request model" 的交互器中,验证 "parameters" 然后 return 各自的值对象作为(部分的)响应模型。
这样验证逻辑就在正确的层,值对象只在验证成功时创建——所以不会创建无效的值对象,也不会浪费性能。
我正在创建一个应用程序,其架构是基于 Uncle Bob's Clean Architecture concepts and DDD。请注意,它是基于 DDD 的 BASED,所以我给了自己与严格 DDD 不同的自由。
为了创建此应用程序,我使用了 C# 和 .Net Standard 2.0
DDD 的原则之一与值对象有关。根据Wikipedia,值对象的定义如下:
Value Object
An object that contains attributes but has no conceptual identity. They should be treated as immutable.
Example: When people exchange business cards, they generally do not distinguish between each unique card; they only are concerned about the information printed on the card. In this context, business cards are value object
现在,我希望我的值对象在某些验证不成功时不允许创建它们。当它发生时,将在实例化过程中抛出异常。我真的打算在那里抛出一个异常,因为架构的核心确实不希望任何无效数据达到那个点。
在进一步讨论这个问题之前,为了给你们更多背景知识,here 是我的架构(注意:仍然不完整):
我在这个架构中遵循的规则是:
- 一个层只能知道它的最内层邻居层的接口
- 一个层无法知道任何最外层的信息
- 层之间的所有通信必须通过接口完成
- 每一层都必须可以独立部署
- 每一层都必须可以独立开发
为了更好地理解图中的箭头,我建议阅读那些 Stack Exchanges 的问题:
Explanation of the UML arrows
https://softwareengineering.stackexchange.com/questions/61376/aggregation-vs-composition
现在,我现在面临的挑战是找到一种使用验证器的好方法。在这一点上,我对我的架构不满意。问题如下:
因为我可以在给定时间实例化数千个值对象,所以我不希望值对象的每个实例都有一个实例方法来执行验证。我希望验证方法是静态的,因为它的逻辑对于每个实例都是相同的。另外,我希望架构的上层可以使用验证逻辑来执行验证,而无需尝试实例化值对象,从而导致抛出昂贵的异常。
问题是:C# 不允许静态方法的多态性,所以我不能做类似的事情:
internal interface IValueObject<T>
{
T Value { get; }
static bool IsValid(T value);
}
如何在不依赖静态方法多态性的情况下实现此功能,同时不浪费内存?
你可以抽象地思考是件好事,但你应该在编写了一些工作代码后进行概括。
一般干净的 on-size-fit-all 架构 DDD 是一个 Mith。实际上 DDD 只适用于 Domain 层。这就是它的美妙之处,它与技术无关。
在我的项目中,我什至没有基础 class 或值对象、实体或聚合根的接口。我不需要它们。所有这些积木都是 POPO (PHP)。
在我看来,干净的架构是使领域层技术不可知,不依赖于任何外部框架的架构。其他层几乎可以是任何东西。
我建议您摆脱 IsValid()
并创建您的值对象 self-checking、always valid 对象。建议使它们不可变,这显然会在这方面有很大帮助。您只需在创建过程中检查一次不变量。
[编辑]
您可能需要将其视为输入验证的第一遍而不是值对象不变强制。如果有大量不安全的数据进入,你想将其转化为值对象,首先在外层的验证过程中处理它——你可以进行所有你需要的性能优化,实现错误逻辑并协调 VO 创建。
在干净的架构中,所有业务逻辑都进入用例交互器。验证规则是业务逻辑的一部分,因此也应该进入用例交互器。
在你的情况下,我建议将你的验证放在采用 "request model" 的交互器中,验证 "parameters" 然后 return 各自的值对象作为(部分的)响应模型。
这样验证逻辑就在正确的层,值对象只在验证成功时创建——所以不会创建无效的值对象,也不会浪费性能。