C# Composition - 不完全确定我是否正确实施

C# Composition - not fully sure I am implementing correctly

最近我学习了更多关于 C# OOP 的知识——特别是如何处理继承、组合和聚合。

我在练习任务的上下文中执行此操作,该任务要求为餐厅类型的服务构建订购 API。具体来说,该任务要求一个菜单。菜单可以有多种类型,例如午餐菜单、晚餐菜单等。每个菜单都有多个类别,例如开胃菜、主菜、甜点等。一个类别可以属于多个菜单。然后每个类别也有子类别,因此例如 Starter 可以有冷热选项。在子类别中然后有多个食物项目,因此对于午餐菜单(菜单)上的开胃菜(类别)中的热菜(子类别),可以有汤,比萨饼等

根据我对任务和 OOP 的理解,这将需要组合而不是继承。这是因为每个 Class 内部都有其他类型的 classes - 菜单有类别,类别有子类别等。

所以我构建了 classes 如下:

菜单 class:

public class Menu
{
    public Menu()
    {}

    public Menu(long Id, string Name)
    {
        this.id = Id;
        this.name = Name;
    }

    private long id;

    private string name;
}

类别class:

public class Category
{
    public Category()
    {}

    public Category(Menu menu, long categoryID, string Name)
    {
        this._menu = menu;
        this.CategoryID = categoryID;
        this.name = Name;
    }

    private Menu _menu;

    public long CategoryID { get; set; }

    private string name { get; set; }

}

子类别class:

public class Subcategory
{
    public Subcategory()
    {}

    public Subcategory(Category category, int subcategoryID, string Name)
    {
        this._category = category;
        this.SubcategoryID = subcategoryID;
        this.name = Name;
    }

    private Category _category;
    private long SubcategoryID { get; set; }
    
    private string name { get; set; }
}

最后是 FoodItem class:

public class FoodItem
{
    public FoodItem()
    {}

    public FoodItem(Subcategory subcategory, long Id, string Name, string Size)
    {
        this._subCategory = subcategory;
        this.Id = Id;
        this.name = Name;
        this.size = Size;
    }

    private Subcategory _subCategory;
    public long Id { get; set; }

    public string name { get; set; }

    public string size { get; set; }
}

所以我所做的是遵循在线示例 - 每个 subclass 中的 superclass 实例被创建并传递到构造函数中。这意味着子 class 不能存在,除非超级 class 也已创建 - 类别需要菜单,子类别需要类别,食品项目需要子类别。

我的问题是:

非常感谢任何方向。

您已确定您的菜单有类别,但以相反的方式实现了它(在您的代码中,您的类别有一个菜单)。引用从叶节点到父节点,而不是父节点包含对其包含的项目的引用集合。

关于您发布的内容,我发现另一件不寻常的事情是所有成员都是私人的。您可以向外界公开属性,有时您将需要一种方法来查看菜单中包含的数据并将其呈现给用户。

我会重写 类 使其看起来更像这样:

public class Menu
{
    public Menu() { }

    public Menu(long id, string name)
    {
        Id = id;
        Name = name;
    }

    public long Id { get; }

    public string Name { get; set; }

    public List<Category> Categories { get; } = new List<Category>();
}

请注意,我对某些人使用了 get,对其他人使用了 get/set。这只是一个假设,但您通常不希望对象的 id 发生变化。同样,初始化列表并保留它 get-only 意味着用户不必在每次使用它时都进行空检查。

添加到另一个答案。

类别没有父类别,但子类别有。但除此之外它们非常相似。所以我会考虑定义一个子类别作为类别的子类型。使它成为一个递归数据结构,允许子...子子类别。

public class SubCategory : Category
{
    public SubCategory(Category Parent, ...) : base(...){
        ParentCategory = Parent;
    }
    public Category ParentCategory { get; }
}

虽然您也可以消除子类别 class,方法是允许类别具有空父类别。

然后一个食品项目有一个类别,它可以是一个子类别的实例。由于每个菜单都有不同的食物,但可能有相同的类别。您应该将其建模为按类别分组的食品列表。也许;

public class Menu {
    public List<FoodItem> FoodItems { get; } = new List<FoodItem>();

    public IGrouping<Category,FoodItems> GroupItems =>
        FoodItems.GroupBy(f => f.Category);
}