正如DDD从业者所建议的那样,业务规则的验证必须在域对象(实体,值对象和域服务)中实现,并且也应该遵循他们自己的上下文,我读过我们应该进行技术验证(例如检查长度,正确的输入格式,正确的数据类型,...)域模型以及应用层之类的地方,以保持域对象清晰。
现在 我的问题是:
如果我们有信用卡号的价值对象等,我们是否应该从我们的价值对象中保留技术验证? 换句话说,"自我验证"当我们处理价值对象时,术语不涉及技术验证?
如果不正确的借记卡号码甚至电子邮件地址有可能破坏业务规则,那么呢?
为了更加清晰,请注意这个代表借记卡号码的价值对象:
public class DebitCardNumber : ValueObject
{
public string Number { get;private set; }
public CreditCardNumber(string number)
{
Validation(number);
this.Number = number;
}
private void Validation(string number)
{
if (String.IsNullOrWhiteSpace(number))
{
throw new CardNumberCanNotBeEmptyException();
}
if (number.Length != 16)
{
throw new CardNumberLengthMustBeSixteenDigitException();
}
int sum = 0;
for (int i = 1; i <= 16; i++)
{
if (!char.IsDigit(number[i - 1]))
{
throw new ValueContainsSomeNonDigitCharacterException();
}
int m = (i % 2 == 0 ? 1 : 2);
int a = (int.Parse(number[i - 1].ToString()) * m);
while (a > 9)
{
a -= 9;
}
sum += a;
}
if ((sum % 10) > 0)
{
throw new ValueIsNotCorrectAsACardNumberException()
{ Message = "Perhaps some digits has been entered in wrong order or they are incorrect." };
}
}
}
根据此代码,有一种验证方法可以执行算法,以找出卡号的格式是否正确? 你认为这种验证是正确的吗?
答案 0 :(得分:8)
正如DDD从业者所建议的那样,业务规则的验证必须在域对象(实体,值对象和域服务)中实现
是
我也读过某个地方,我们应该从域模型和应用层之类的地方放置技术验证(例如检查长度,正确的输入格式,正确的数据类型......),以保持域对象清晰。
这里有点困惑;重点是实体不应该担心一堆输入验证,这不是他们的工作(职责分离)。因此,我们不是将原始数据(字符串,基元)传递给模型中的实体,而是首先使用基元构造实体将识别的值类型,然后将这些实体传递给。
可以使用基元来创建格式良好的值类型的规则在值类型本身(构造函数)或为此目的提供的专用工厂中正确实现。应用程序组件有责任在将该值传递给模型之前,从它收到的消息/ DTO中创建值类型。
因此,在您的示例中,DebitCard验证逻辑看起来就像它在正确的位置。
谨慎 - 你的模特随着时间的推移而发展;当模型发生变化时,您仍然需要能够读取模型早期版本所写的数据。添加将当前数据视为无效的验证规则可能会变得混乱 - 因此您需要确保验证规则具有业务动机。您是通过确保借记卡号码具有有效的校验和来节省资金/削减成本吗?
(例如:假设客户提交的采购订单中包含无效的卡号。企业是否希望拒绝该订单,或接受该订单,但推迟采取行动,直到付款方式有效为止是否提供?如果是后一种选择,您需要确保验证逻辑不会妨碍接受订单。)
答案 1 :(得分:3)
如果我们有信用卡号的价值对象等等,我们还是 应该从我们的价值对象中保留技术验证吗?其他 单词“自我验证”一词不涉及技术 我们处理价值对象时的验证?
正确。应对域(实体,域服务,vos等)进行建模,使其强制执行业务规则,而不是技术问题。您的域名可能需要区分DebitCards和CreditCards,但我怀疑业务是否关心卡号本身的格式。格式&amp;卡号的正确性对于基础结构非常重要,因此可以在该层中强制执行格式化规则。
答案 2 :(得分:1)
在我看来,你的方法在大多数情况下都适用。
如果号码无效,则不是借记卡号码。
假设您的借记卡号码无法验证。您的布尔valid
设置为false,或者您的代码对您不利:它不是借记卡号。
如果您仍想存储该号码,可能出于安全或用户体验的目的,您应该在另一个对象中执行此操作,可能在“输入的表单”值对象内。
答案 3 :(得分:1)
我不认为你的例子是技术验证规则 - 我认为它是借记卡的域规则 - 如果在银行领域,借记卡号必须遵循某种模式,那么这是需要强制执行的域规则。
所以我认为你的解决方案是正确的。