Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 在进行领域驱动设计时,如何正确利用价值对象验证?_Oop_Language Agnostic_Domain Driven Design - Fatal编程技术网

Oop 在进行领域驱动设计时,如何正确利用价值对象验证?

Oop 在进行领域驱动设计时,如何正确利用价值对象验证?,oop,language-agnostic,domain-driven-design,Oop,Language Agnostic,Domain Driven Design,我有一个简单的实体顺序伪代码: class Order{ private int quantity; private Date orderDate; private Date shippingDate; public Order(int quantity, Date orderDate, Date shippingDate){ if(quantity <= 0){ throw new Exception("Invalid quant

我有一个简单的实体
顺序
伪代码:

class Order{    
    private int quantity;
    private Date orderDate;
    private Date shippingDate;

    public Order(int quantity, Date orderDate, Date shippingDate){
        if(quantity <= 0){ throw new Exception("Invalid quantity")}
        if(shippingDate < orderDate){ throw new Exception("Invalid shippingDate")}
        if(...more validation...){....throw Exceptions...}

       //assign values if everything is OK
    }
}
如您所见,验证逻辑在
文本字段
验证和实体验证之间重复。
我试图通过创建
Quantity
类、
OrderDate
类和
ShippingDate
类,将值对象的概念引入到我的实体中。因此,我的
订单
实体变成如下:

class Order{    
    private Quantity quantity;
    private OrderDate orderDate;
    private ShippingDate shippingDate;

    public Order(Quantity quantity, OrderDate orderDate, ShippingDate shippingDate){
        //assign values without validation I think??!!
    }
}
例如,类别数量为:

班级数量{

private int quantity;
public Quantity(int quantity){
        if(quantity <= 0){ throw new Exception("Invalid quantity")}
        this.quantity=quantity;
}
private int数量;
公共数量(整数数量){
如果(数量)
  • 如果任何
    数量
    在您的域中不能为负值,无论上下文如何,这都是非常有意义的
  • IMO您的
    Quantity
    构造函数中的验证用于确保应用程序正确使用类。它引发异常,这些异常是针对异常状态的,而不是预期的工作流。因此,它的用途与web表单验证完全不同,web表单验证确保应用程序的正确使用用户。它需要无效的输入并处理它。我在这里看不到真正的重复,至少不会在不违反单一责任原则的情况下消除
  • 我认为情况并非如此。您有
    if(shippingDate
    -您计划如何在value对象中验证这一点
  • 啊,你看到问题了。相同的答案:此验证属于订单实体。此外,你不必对所有内容都使用值对象。如果订单日期或发货日期本身没有固有的约束,只需继续使用
    日期
  • 这似乎是一个单独的问题,我看不出与价值对象有任何关联

  • 这些问题很多,你可能想把它们分解成单个问题

    问题2至5在很大程度上取决于各种因素,并取决于意见

    但以下是我对问题1(以及问题3和4)的回答:

    聚合负责其完整性。而不是聚合根。只要聚合作为一个整体保持有效,聚合中的每个项目都可以进行自己的验证

    状态验证(作为正确的金额或不是负的金额)可以在相应的类中完成。相互依赖的状态验证,如
    ShippingDate>=OrderDate
    ,可以在更高的级别上完成,例如在聚合根中

  • 聚合根应该在其聚合中强制执行不变量,但它们不会进行所有验证,尤其是在构造时不进行验证,这通常在构造函数或工厂中进行。 事实上,将尽可能多的(非上下文特定的)不变量移动到构造函数和工厂是有益的。我认为拥有实体比在聚合根或实体本身上重复使用
    ValidateThis()
    ValidateThis()
    方法要好得多

  • 基本上有3种验证:客户端验证、应用程序验证(在控制器或应用程序层服务中)和域验证(域层)。客户端验证是必需的,不能重复使用。应用程序验证可以依赖于域验证,在您的示例中,域验证意味着只调用Quantity构造函数并处理它引发的异常。但是,它也可以有自己的一组特定于应用程序的非域规则-例如,再次验证
    密码
    字段安装其
    密码\u确认

  • 与总是有效的实体一样,值对象最好是不可变的,这意味着当你新建它们时只需要验证一次。然而,这是内在的验证,你可以在包含它们的实体中完美地进行外围验证(例如,列表中此类值对象不能超过3个,值对象A始终与值对象B一起,等等)

  • 这是情境验证,而不是ShippingDate内在不变量的验证。因此,Order应负责检查
    ShippingDate>=OrderDate
    ,独立于这些值对象的有效性

  • 当一个对象的构造逻辑足够复杂,以致于它本身就是一种责任,并且由于SRP,因此不适合对象的构造函数或使用者时,应该使用工厂。工厂确实包含构造时验证逻辑,就像构造函数一样,这使它们也成为各种不变的执行器


  • 你说你有一个实体
    Customer
    ,但是你正在显示
    Order
    @DanielHilgarth的代码对不起我的错误。我现在修复了它。在value对象之外重用验证很简单。将验证逻辑提取到一个返回bool的静态方法。构造函数将调用该方法,如果返回false,则抛出。The web层可以询问Quantity.IsValid(值)正如前面提到的,您的问题不是是否有对象值。不必要地添加对象值并不会使事情变得更简单。您需要区分两种检查类型:1)检查是否应用了域级约束。2)检查用户输入,web级验证。回答得好。对于第2点,我想补充一点,总体而言,这是一个非常有趣的问题,没有任何好的解决方案。整合验证规则会很好,但是由于语言和框架的限制,这可能会很困难。示例尝试类似于ASP.NET MVC中的验证,其中将验证属性转换为客户端JavaScript。此方法和相关方法的问题在于,必须使用仅在调用实体时才保护实体的属性。此外,验证上下文可能会影响规则本身,这是另一个原因
    private int quantity;
    public Quantity(int quantity){
            if(quantity <= 0){ throw new Exception("Invalid quantity")}
            this.quantity=quantity;
    }