代码之家  ›  专栏  ›  技术社区  ›  Tigraine

域模型中的Setters

  •  2
  • Tigraine  · 技术社区  · 15 年前

    在DDD的上下文中,域模型上的设置器是一种代码气味。 应该避免使用它们,原因很简单,它们不是域的一部分。其中没有领域专家可以理解的名词,对数据的更改应该通过特定的方法来实现。

    customer.StreetName = ...
    customer.City = ...
    

    而正确的方法是 customer.ChangeAddress

    如果我不能构造一个客户实例而没有一个大的构造函数来接受所有的参数,或者做一些反射魔法,那么我如何让客户实例来运行我的测试呢?我在后端使用NHibernate,所以NHibernate已经做了一些反射魔法来填充这些字段。

    有什么建议吗?

    2 回复  |  直到 15 年前
        1
  •  3
  •   Arnis Lapsa    15 年前

    在经典(非CQRS)DDD中,一个好的做法是将所有数据分解为值对象,这样您的实体就简化为它们的主要功能:维护标识。

    在您的示例中,客户应该引用一个Address ValueObject,并拥有一个ChengeAddress方法,该方法应该简单到:

    public void ChangeAddress(Address address)
    {
       //Consistency rules are here
       _address = address;
    }
    

    尽量将逻辑从实体移动到值对象。它们本质上更易于测试,因为良好的值对象很小且不可变。您可以使用构造函数来实例化给定状态下的VO并对其进行练习(通常通过调用返回另一个已转换的VO实例的方法)。

    最后但并非最不重要的一点是,根据我的经验,如果测试领域模型需要额外的基础设施(如反射或任何其他工具),那么就错了(通过引入不必要的耦合)。

        2
  •  1
  •   Community Mohan Dere    8 年前

    AutoFixture

    再加上一点反省,爱和领域就变得非常可测试了:

    namespace Unit{
      using System;
      using System.Linq.Expressions;
      public static class ObjectExtensions{
        public static T Set<T,TProp>(this T o,
          Expression<Func<T,TProp>> field,TProp value){
    
          var fn=((MemberExpression)field.Body).Member.Name;
          o.GetType().GetProperty(fn).SetValue(o,value,null);
          return o;
        }
      }
    }
    

    用法:

    myUberComplexObject.Set(x=>x.PropertyOfIt, newValueOfIt);
    

    你至少应该试着把那些“大屁股”的物体分成更小的。试着建立一个层次结构(只需确保它符合无处不在的语言)。