我有一个带有OrderItems的域模型Order。
订单必须
我的订单结构如下
public Order(Manager manager, IList<OrderItem> orderItems)
{
if(manager == null) throw new ArgumentNullException(nameof(manager));
if(orderItems == null) throw new ArgumentNullException(nameof(orderItems));
if(orderItems.Count == 0)
throw new Exception("List must contain at least one item.");
foreach(var item in orderItems)
AddItem(item);
//assign values
this.manager = manager;
...
...
}
Manager manager;
IList<OrderItem> orderItems;
...
void AddItem(OrderItem orderItem)
{
if(orderItem == null) throw new ArgumentNullException(nameof(orderItem));
if(orderItems.Contains(orderItem))
throw new Exception("Order Item duplicate");
orderItems.Add(orderItem);
}
void CreateNewOrder(int managerId, List<int> itemIdList)
{
Manager manager = managerRepo.FindById(managerId);
List<OrderItem> itemList =new List<OrderItem>();
foreach(int itemId in itemIdList)
itemList.Add(itemRepo.FindById(itemId));
Order order = new Order(manager, itemList);
orderRepo.Add(order);
}
我认为它接近持久性模型,而不是领域模型。
如果我像下面这样编码怎么办?
public Order(Manager manager)
{
if(manager == null) throw new ArgumentNullException(nameof(manager));
this.manager = manager;
...
...
}
public void AddItem(OrderItem orderItem)
{
if(orderItem == null) throw new ArgumentNullException(nameof(orderItem));
if(orderItems.Contains(orderItem))
throw new Exception("Order Item duplicate");
orderItems.Add(orderItem);
}
public void ReadyForPersistence()
{
if(orderItems.Count == 0)
throw new Exception("Not ready for persistence");
}
void CreateNewOrder(int managerId, List<int> itemIdList)
{
Manager manager = managerRepo.FindById(managerId);
Order order = new Order(manager);
//Here order has zero item, does this mean order is in invalid state?
foreach(int itemId in itemIdList)
order.AddItem(itemRepo.FindById(itemId));
order.ReadyForPersistence();
orderRepo.Add(order);
}
我是否误解了“始终有效的状态”?
如何正确实施“始终有效的状态模型”。
答案 0 :(得分:1)
首先,我想说的是,持久性与您要问的无关紧要。问题确实是:空订单确实在您要建模的域中有效吗?
如果空订单在您的域中是错误的或没有任何意义,我会说立即继续并在代码中强制执行此不变式。不允许任何方法完成,以免使订单处于不一致状态。应用程序级代码(在这种情况下为CreateNewOrder
方法)的末尾具有有效顺序并不重要。另一个实现者可能会犯一个错误,而忘记在其中添加项目。在这种情况下,您的订单将不会强制执行所需的不变式。
请注意,是否有空订单确实取决于您所从事的行业。 请与您的主题专家交谈,以检查空订单是否只是名称不同的东西。您可能会发现空订单是有效的,它具有自己的规则和操作,但是它们有另一个名称,并且具有一组不同的不变式,如果这样做,它会使您的工作变得简单得多:作为模型一部分的“订单草稿”,将作为订单的工厂有机地工作。
答案 1 :(得分:0)
处理使实体始终有效的设计难题的一种方法是识别状态机的存在。实体在其整个生命周期中不限于保留单个类型。实体是唯一可识别的事物,有时可以在类型之间转换(变形)。
虽然一个订单中必须包含至少1个订单项,但购物车可以包含0到n个商品。
一个过渡状态如何?好吧,您使实体成为某种可寻址的事物,例如引用。将实体设为地址后,就可以自由使用不可变的对象。
一个不变的对象只是一个持久的数据结构,一旦构造就无法使其状态发生变化。相反,您可以对其执行函数/方法,以返回原始对象的修改后的副本,并应用一些有效的更改。这意味着调用任何给定的函数可能会返回相同类型(带有新数据)或新类型(例如状态机转换)。考虑到这一点,您可以在工作流下游的某个地方从ShoppingCart
到Order
进行实体转换。
可以用支持协议的语言(Clojure,Swift,Groovy等)或支持联合类型的语言(F#,Elm,Haskell,Reason,OCaml)完成这种事情。使用任何一个都允许相同的消息(例如place
)具有不同的行为。 place
上的ShoppingCart
函数将验证它具有转换为Order
所需的一切。
我并不是说这是解决您问题的最终方法。我只是把它作为处理这种问题的一种方式。