C#DDD:更改购物篮中的物品数量(如果有)

问题描述 投票:0回答:2

我尝试为第一个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();
}
domain-driven-design single-responsibility-principle
2个回答
0
投票

如何传递允许AR像basket.changeItemQuantity(itemId, quantity, inventoryService)中那样查询给定项目的库存的服务?

有些人不喜欢这种风格,会更喜欢在应用程序服务中解析清单,然后将其提供给AR,例如basket.changeItemQuantity(itemId, qty, qtyOnHand)。我更喜欢这里的第一种方法,尽管将稍微涉及单元测试。

第三种方法是实现域服务以协调逻辑。您将当前在应用程序服务中拥有的域逻辑提取到该域服务,并将用例处理从应用程序服务委托给域服务。仅凭该规则可能就算过高了,只会使您趋向贫血模型。

关于您的设计建议的几点评论:

  • 您不应该分发非根实体引用。篮子应提供更改数量的界面。

  • 从篮子式AR引用仓库AR的第二个建议也将违反AR设计规则:AR应仅按ID引用其他AR。这有助于使AR保持较小且集中的状态,并让开发人员查看每个AR真正拥有和保护的数据。您也将不太想在同一笔交易中更改两个AR。

  • 从AR边界外部引用的数据被认为是陈旧的。您可能想探索将商品添加到购物篮中的情况,以便稍后发现库存已经耗尽。那你怎么办呢?考虑这些场景将指导您建立一个更加面向业务的模型,该模型可以处理这种复杂性,而不是试图使所有事物都成为一个高度一致的不变式,而最终会导致一个不切实际的模型与域需求不符。


0
投票

好,关于DDD的问题。还有一些非常有趣的讨论。

我目前正在编写Shop应用程序,因此这对我和我的团队来说都是一个非常有用的问题。

我首先要说的是,您应该与仓库,销售和管理团队进行讨论,以更好地了解这些情况。如果有2个销售人员同时致电仓库,并询问当前的库存以及他们是否可以出售,这将对您的实现产生重大影响。

技术/代码

一般性讨论

  1. 如果将某个项目添加到购物篮中,实际上应该减少库存吗?考虑您有5件库存。 5个篮有1个物品;没人能将此物品添加到他们的购物篮中吗-如果他们真的准备好购买-现有的购物篮必须有多陈旧?考虑:还剩5项,1个月前将5项添加到了购物篮中。这应该阻止准备购买的用户吗?

这是我的技术观点(很乐意进一步讨论)...@plalx有一些很棒的主意,我认为它实际上介于两者之间。

您真的只想问一个问题-我可以将此数量的这个物品添加到这个购物篮中吗...

Basket basket = _basketStore.Get(1);
basket.ChangeQuantity(item, quantity, availability);

//定义

public interface IAvailabilityProcessor {
  bool AvailableForBasket(item, quantity);
}

public class Basket {
  public void ChangeQuantity (Item item, int quantity, IAvailabilityProcessor processor) {
     var canBeAdded = processor.AvailableForBasket(item, quantity);

     if (canBeAdded) {
        this.Add(item, quantity);
     }
}

[我通常可以这样做,花一些时间谈论这些事情的确切实现,但是我现在就这样说-请反馈或提出问题

© www.soinside.com 2019 - 2024. All rights reserved.