Domain driven design 一切似乎都是一个聚合的根

Domain driven design 一切似乎都是一个聚合的根,domain-driven-design,Domain Driven Design,我想在一家餐馆里做菜单组成的模型。我仅围绕3个概念创建了一个非常小的有界上下文:菜单,类别,产品 菜单由不同的产品组成,每个菜单中的每个产品都被归入某个类别(例如,“参赛者”、“第一道菜”、“第二道菜”、“甜点”…) 问题是,在我看来,一切似乎都是一个实体 例如,删除菜单时,不会删除任何产品或类别。其他3个概念也会发生同样的情况 关于UI,菜单将像层次结构一样使用: Menu1 Category1 Product1 Product2 Categor

我想在一家餐馆里做菜单组成的模型。我仅围绕3个概念创建了一个非常小的有界上下文:
菜单
类别
产品

菜单由不同的产品组成,每个菜单中的每个产品都被归入某个类别(例如,“参赛者”、“第一道菜”、“第二道菜”、“甜点”…)

问题是,在我看来,一切似乎都是一个实体

例如,删除菜单时,不会删除任何产品或类别。其他3个概念也会发生同样的情况

关于UI,菜单将像层次结构一样使用:

Menu1
    Category1
        Product1
        Product2
    Category2
        Product3
        Product4
我想知道如何建模。我应该把它们做成3块吗?那么,为了像上面的层次结构一样被消费,一个用户应该如何组成一个菜单呢


谢谢。

如果您有一个菜单作为当前安排的聚合根目录,那么如果您想在不同的菜单上重复使用相同的产品,会发生什么情况?从聚合根外部,您将无法保存对它的引用

相反,我认为将菜单和产品(问厨师他会如何称呼食物或菜单项!)作为聚合根是很好的,因为它们都存在并且有自己的特性(随着时间的推移,你可能会有不同的菜单,一个菜单可能由其他菜单上使用过的食物组成)

将类别作为价值对象可能更合适(同样,也许厨师会称之为课程?)-您有多少类别(我相信这些课程可能是固定的)?类别是否有自己的生命周期和身份?每个产品上的可枚举项可以很好地满足这一要求

你还提到删除。。。这听起来像是一个技术基础设施术语。这有两个问题:

  • 如果您执行了上述操作并分成两个聚合根(菜单和产品),那么当菜单引用产品时,您将如何处理产品的删除?这变成了一个跨两个聚合根的事务,很难实现(DDD的主要思想之一是定义事务边界并通过聚合实现不变量-从外部对聚合根进行的任何外部操作都应该使其处于一致状态)

  • 想想厨师或餐厅经理会做什么——他们会删除菜单,还是将其存档,或使其不再可供选择

  • 沃恩·弗农(Vaughn Vernon)的有效骨料设计将有助于巩固上述内容

    就代码而言,C#中的psuedo实体模型如下所示:

    public Object HandleGetMenuCommand(
        string menuName,
        IMenuRepository menuRepository,
        ProductRepository productRepostiory)
    {
        Menu menu = menuRepository.Get(new MenuId(menuName));
        List<ProductIds> productsInMenu = menu.Products;
        List<Products> products = productRepostiory.GetMany(productsInMenu);
        List<string> categories = ... // get a list of unique categories from products
    
        // now assemble products by category...
        foreach(var category in categories)
        {
                var productsInCategory in products.Find(x => x.Category == category);
                foreach(var product in productsInCategory)
                {
                    // add this to a list...
                }
        }
    
        var clientData = new {
            name = menu.Name,
            // add in the products that were assembled by category above
        }
    
        return clientData;
    }
    
    公共对象HandleGetMenuCommand(
    字符串menuName,
    IMenuRepository menuRepository,
    产品存储库(ProductRepository)
    {
    Menu Menu=menureposition.Get(新的MenuId(menuName));
    列出产品菜单=菜单.产品;
    列出产品=ProductRepository.GetMany(productsInMenu);
    列表类别=…//从产品中获取唯一类别的列表
    //现在按类别组装产品。。。
    foreach(类别中的var类别)
    {
    var productsInCategory在products.Find中(x=>x.Category==Category);
    foreach(productsInCategory中的var产品)
    {
    //将此添加到列表中。。。
    }
    }
    var clientData=new{
    name=menu.name,
    //添加按上述类别组装的产品
    }
    返回clientData;
    }
    
    我认为您试图在DDD中投入太多的精力,而不是仅仅通过观察“现实世界”来关注这个领域的简单性。请让我先用一种简单的OO方法,然后再谈谈如何使用DDD来看待它。 所以你想要菜单,这样餐馆的顾客可以看菜单,选择他们想吃的任何东西。让我们假设现在每个工作日只有一份午餐、晚餐的菜单。 餐厅经理应该能够创建此菜单,并随时更改它。 这是我们的第一个用例

    menu = new Menu("monday lunch", starters, mainEntrees, desserts, drinks);
    
    其中每个参数都是值对象列表(乍一看)。 只要看看现实世界,菜单就是对你在餐馆里能吃到的食物的描述,这些描述是不可变的对象(价值对象),到目前为止,我们不需要任何其他东西。 目前,我们只有一个聚合根,即菜单。它具有全局标识,并对一组对象进行分组,并且具有不变量。我将使用哪个类来建模主菜、甜点?字符串…到目前为止,一个字符串实例就足够了。 菜单呢?我们可以有很多菜单,一个是星期一的,一个是星期二的,一个是星期五晚上的等等,每个菜单都有自己的全球标识,所以我们可以确定菜单的位置。 如果餐厅经理想增加一种新的甜点呢

    menu = menuRepository.get(menuId);
    menu.add(aDessert); 
    
    够了。 到目前为止,我们只有一个菜单聚合根及其存储库。 我想这是你问的

    然而,我认为你错过了价格。菜单上的每一行都有价格,不同菜单上的两个相同的甜点如果是午餐或晚餐可能有不同的价格,因此更现实的方法似乎是:

    menu = new Menu("monday lunch", starters, mainEntrees, desserts, drinks);
    
    其中,开胃菜、主菜、甜点、饮料都是MenuLine类型的集合。 现在,如果客户告诉服务员给他带点吃的东西,会发生什么?需要创建一个新订单,以保持客户要求的进度,以便稍后创建发票。 此订单需要知道客户要求的食物,我是指客户点的菜单项。到目前为止,我们正在使用价值对象对甜点、饮料等进行建模。现在,我们应该为客户可以选择的选项提供某种形式或标识符,以便我们在订单上下文(如订单)中使用某些唯一标识符。这是我们决定需要另一个聚合根(你称之为产品)的地方。我更愿意称之为食物或类似的东西。 那么什么时候
    food = new Food("sushi");
    foodRepository.add(food);
    
    food = foodRepository.getBy(foodId);
    menu = menuRepository.findByCriteria(mondayNight)
    menu.addAt(food, tenDollars);
    
    addAt(food, tenDollars) {
    mainEntrees.add(new MenuItem(food.id, food.description, tenDollars)
    }
    
    Menu {
    List starters;
    List entrees;
    List desserts;
    List drinks;
    }