【问题标题】:How much should I enforce the concept of entity and value object in DDD?我应该在 DDD 中执行多少实体和值对象的概念?
【发布时间】:2013-08-13 02:07:06
【问题描述】:

我正在使用 DDD 开发一个 C# 项目。我写了一些类。一些属于实体类别,另一些属于值对象类别。我的问题是,为了符合实体和值对象的定义,必须或应该做多少工作?

实体:

  • 禁止公共构造函数。必须使用工厂和/或静态方法,以保证对象的唯一性(在具有 id 的内存中)。
  • 运算符 ==、!= 重载和 Equals 方法覆盖,因此比较基于对象引用以外的其他内容;身份证

值对象:

  • 允许公共构造函数。工厂,静态方法是允许的,并且可以实现某种缓存,以(可选)保证对象的唯一性(如字符串实习)。
  • 运算符 ==、!= 重载和 Equals 方法覆盖,因此比较基于两个对象的所有值。相反,也可以使用结构。
  • 不可变

这些是可以强制执行这些概念的可能性,但是,这些是强制性的吗?因为创建这些工厂、那些静态方法、重载和覆盖所有这些方法似乎是一个巨大的负载或少量工作,应用 DDD 概念。

我应该走多远?

【问题讨论】:

    标签: c# design-patterns architecture domain-driven-design


    【解决方案1】:

    有一个我很喜欢的编程原理,叫做KISS

    底线是尽你所能,不要仅仅因为你听说过或遇到过指导方针就去做事并遵循指导方针。而是从基本功能开始,然后根据需要不断添加内容。

    例如,您谈到了工厂。我通常不使用它们,除非对象创建很复杂或者我想强制执行某些条件,或者当您谈到运算符重载以进行比较时,除非我需要实际进行比较或在我的代码中需要它,否则我不会这样做。我会尽可能应用的一件事是不可变性,不仅因为它适用于值对象,还因为它是多线程支持的好工具,因为不可变对象在创建后无法修改。

    总结:从简单开始,根据需要添加内容。

    【讨论】:

    • 所以,对于值对象,您应用了不变性,但在需要之前您不会覆盖或重载任何东西?您严格遵守 KISS 原则?
    • @DavidKhuu 总的来说,是的,我不喜欢 strictly 这个词,但是是的,我会尝试添加我需要的东西,或者如果我从需求分析中发现我肯定将来会需要它们。说实话,我从错误中吸取了教训,你也一样。
    【解决方案2】:

    从简单开始并不断发展。

    例如: 假设我有一个 PendingOrder 实体,我开始使用它:

    应用层:

    @Transactional
    @Override
    public PendingOrder placeOrder(Address deliveryAddress, Date deliveryTime) {
        PendingOrder pendingOrder = new PendingOrder(
                pendingOrderRepository.nextTrackingId(), deliveryAddress,
                deliveryTime);     //by constructor
        pendingOrderRepository.store(pendingOrder);
        return pendingOrder;
    }
    

    后来当客户需要验证是否有可用的餐厅提供送货信息时,我引入了 PendingOrderFactory 来强制执行一些域约束:

    应用层:

    @Transactional
    @Override
    public PendingOrder placeOrder(Address deliveryAddress, Date deliveryTime) {
        PendingOrder pendingOrder = pendingOrderFactory.placeOrderWith(
                deliveryAddress, deliveryTime);//refactor to factory
        pendingOrderRepository.store(pendingOrder);
        return pendingOrder;
    }
    

    领域层:

    public PendingOrder placeOrderWith(Address deliveryAddress,
            Date deliveryTime) {
    
        if (restaurantRepository.isAvailableFor(deliveryAddress, deliveryTime)) {
            return new PendingOrder(pendingOrderRepository.nextTrackingId(),
                    deliveryAddress, deliveryTime);
        } else {
            throw new NoAvailableRestaurantException(deliveryAddress,
                    deliveryTime);
        }
    
    }
    

    另一方面,可以使用一些代码生成工具。这就是我们在java中使用的

    @ToString(of = "trackingId") //print PendingOrder.trackingId
    @EqualsAndHashCode(of = "trackingId")//compare trackingId when Equals
    public class PendingOrder {// this is an entity
    
    @ToString //print all fields
    @EqualsAndHashCode //compare all fields
    @NoArgsConstructor
    // @NoArgsConstructor for frameworks only
    public class Address {// this is a value object
    

    而且,我们只在必要时添加它们,通常,当你编写测试报告显式错误时需要@ToString,当你使用 mocks 编写测试时需要@EqualsAndHashCode。

    例如:pendingOrderFactory 是一个 mock,我们验证它是使用给定参数(deliveryAddress,deliveryTime)调用的,mock 框架通过 Equals 对此进行检查,当我们未能满足预期时,会显示一个报告。模拟框架调用 ToString 来指示哪个对象打破了预期。

    @Test
    public void placesAPendingOrder() throws Exception {
        final PendingOrder pendingOrder = new PendingOrderFixture().build();
        final Address deliveryAddress = pendingOrder.getDeliveryAddress();
        final Date deliveryTime = pendingOrder.getDeliveryTime();
    
        context.checking(new Expectations() {
       {
                allowing(pendingOrderFactory).placeOrderWith(deliveryAddress,
                        deliveryTime);//need to implement equals
                will(returnValue(pendingOrder));
    
                oneOf(pendingOrderRepository).store(pendingOrder);//need to implement equals
            }
        });
    
        PendingOrder order = target.placeOrder(deliveryAddress, deliveryTime);
    
        assertThat(order, is(pendingOrder));
    }
    

    希望这对 Java 示例有所帮助和抱歉,因为我是 C# 白痴 :(

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-24
      • 2010-11-25
      • 1970-01-01
      • 2010-10-04
      • 2010-12-07
      • 1970-01-01
      • 2013-01-31
      相关资源
      最近更新 更多