domain-driven-design - C# DDD:更改篮子项目数量(如果可用)
问题描述
我尝试按照第一个 DDD 项目进行设计。我在 BasketItem 中创建了一个方法来更改我的篮子中当前项目的数量,只有在仓库中有足够的项目时才能更改数量。
我在应用程序服务中进行此检查,但我不喜欢,因为 BasketItem.ChangeQuantity 是一个公共方法,任何人都可以在不检查数量的情况下调用此方法。
为防止输入不正确的数量,我想将控件移至 ChangeQuantity。这个解决方案正确吗?考虑到 SOLID 方法会有太多的责任?
你推荐哪条路?
public class Basket : Entity, IAggregateRoot
{
public long BasketId { get; protected set; }
public long UserId { get; protected set; }
private List<BasketItem> _basketItems;
public virtual IReadOnlyCollection<BasketItem> BasketItems => basketItems?.ToList();
}
protected Basket() { }
public class BasketItem : Entity
{
public Guid Guid { get; protected set; }
public decimal Price { get; protected set; }
public int Quantity { get; protected set; }
public virtual Basket Basket { get; protected set; }
public virtual Product Product { get; protected set; }
protected BasketItem() { }
public IStatusGeneric ChangeQuantity(int quantity)
{
var errorStatus = new StatusGenericHandler();
//How to get avaiable quantity from WarehouseProduct?????????
//var avaiable = Basket.Warehouse.ProductQuantityAvaiable(Product);
if (avaiable < quantity)
{
var errorStatusMessage = $"There are only {avaiable} avaiable product of {Product.Code}.";
if (productQuantityInBasket > 0)
{
errorStatusMessage += $"Current basket have already {productQuantityInBasket}";
}
errorStatus.AddError(errorStatusMessage);
return errorStatus;
}
haveProduct.ChangeQuantity(quantity);
return errorStatus;
}
}
public class Warehouse : Entity, IAggregateRoot
{
public long WarehouseId { get; protected set; }
public string Name { get; protected set; }
private List<WarehouseProduct> _warehouseProducts;
public virtual IReadOnlyCollection<WarehouseProduct> WarehouseProducts => _warehouseProducts?.ToList();
}
public class WarehouseProduct : Entity
{
public Guid Guid { get; protected set; }
public int Quantity { get; protected set; }
public virtual Warehouse Warehouse { get; protected set; }
public virtual Product Product { get; protected set; }
private WarehouseProduct() { }
public void ChangeQuantity(int deltaQuantity)
{
Quantity += deltaQuantity;
}
}
第二个解决方案是将仓库带入篮球。这样我就可以访问仓库的所有元素以查找可用数量。这也将允许我将篮球与特定仓库相关联,以便我可以管理多个仓库
public class Basket : Entity, IAggregateRoot
{
public long BasketId { get; protected set; }
public long UserId { get; protected set; }
public Warehouse Warehouse { get; protected set; }
private List<BasketItem> _basketItems;
public virtual IReadOnlyCollection<BasketItem> BasketItems => _basketItems?.ToList();
}
解决方案
传递一个允许 AR 查询给定项目库存的服务怎么样basket.changeItemQuantity(itemId, quantity, inventoryService)
?
有些人不喜欢这种风格,他们更喜欢在应用程序服务中解析库存,然后将其提供给 AR,例如basket.changeItemQuantity(itemId, qty, qtyOnHand)
. 我更喜欢这里的第一种方法,尽管单元测试会稍微多一些。
第三种方法是实现域服务来编排逻辑。您可以将您当前在应用程序服务中的域逻辑提取到该域服务,并将用例处理从应用程序服务委托给域之一。对于这条规则来说,这可能是矫枉过正,只会把你推向一个贫血的模型。
关于您的设计建议的一些评论:
您不应该分发非根实体引用。篮子应该提供改变数量的接口。
从 Basket AR 中引用仓库 AR 的第二个提议也违反了 AR 设计规则:AR 只能通过 id 引用其他 AR。这有助于让 AR 保持小而专注,并让开发人员看到每个 AR 真正拥有和保护哪些数据。您也不太愿意在同一事务中更改两个 AR。
从 AR 边界之外引用的数据将被视为陈旧。您可能想探索将商品添加到购物篮的场景,但片刻之后才发现库存已经用完。那你怎么办呢?考虑这些场景将引导您走向一个更加面向业务的模型,该模型可以处理这些错综复杂的问题,而不是试图让一切都成为一个强一致的不变量,最终导致一个不切实际的模型与领域需求不一致。
推荐阅读
- r - Boxplot not displaying correctly
- python - Running Python function at defined intervals
- python - 更改文件夹中pdf文件的日期格式
- reactjs - ReactJS - 用 axios 替换 fetch API 不起作用
- java - 在运行时(通过 ScriptEngine)从 Java 执行时如何测量 Groovy 代码覆盖率?
- javascript - 向 API 发出请求时,视图上看不到任何数据
- python-3.x - Sklearn AdaBooster 和基础估计器
- trimesh - 为 trimesh 生成网格和光线交点
- android - Android Dialog Fragment RecyclerView 包装内容但基于约束的最大高度?
- ms-access - 如何在 MS Access 中安装 MROUND 功能?