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

Posted

技术标签:

【中文标题】C# Composition - 不完全确定我是不是正确实施【英文标题】:C# Composition - not fully sure I am implementing correctlyC# Composition - 不完全确定我是否正确实施 【发布时间】:2021-03-08 21:40:53 【问题描述】:

所以最近我一直在学习更多关于 C# OOP 的知识——特别是如何使用继承、组合和聚合。

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

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

所以我构建了如下类:

菜单类:

public class Menu

    public Menu()
    

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

    private long id;

    private string name;

类别类:

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; 


子类别类:

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 类:

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; 

所以我所做的就是按照在线示例进行操作——创建每个子类中的超类实例并将其传递给构造函数。这意味着除非还创建了超类,否则子类不能存在 - Category 需要 Menu,子类别需要类别,而 fooditem 需要子类别。

我的问题是:

我现在遇到的问题是实例化 FoodItem。要创建 FoodItem,是否需要创建 Menu 对象,然后创建 Category 对象并将 Menu 对象放入,创建子类别并将 Category 放入,然后创建 FoodItem 并将子类别放入?那会是正确的吗?还是我只是创建一个 FoodItem,其余的都是自动创建的?我认为第一个选项是正确的,但想澄清一下。 我的假设是否正确,即合成是正确的方法?还是继承更好? 为了完成任务,我需要能够创建 FoodItems 并发布到 API。假设我做问题 1 的方法是正确的,我将如何创建 FoodItem 所需的超类?

非常感谢任何方向。

【问题讨论】:

【参考方案1】:

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

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

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

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 意味着用户不必在每次使用它时都进行空检查。

【讨论】:

谢谢,我明白你的意思是让一个项目属于超类。然后我是否也可以进一步实现这一点,所以类别将有一个子类别列表等? 刚刚想到了这个,如果Categories 存在于Menu 对象中,我是否将Menu 从Category 类的构造函数中取出来?这是否意味着即使菜单不存在我也可以创建类别? 是的,是的。子实体类型不需要知道他们的父母就可以存在。我肯定会从Category 类中删除Menu,从Subcategory 类中删除Category,从FoodItem 类中删除Subcategory。它将解决您的“如何创建 FoodItem 而无需先创建菜单、类别和子类别?”的问题? 如果我希望相反的情况成立怎么办?所以如果存在菜单、类别和子类别,我只能创建一个 fooditem? 我认为您需要一个单独的模型。我们构建数据的方式有时会有所不同。例如,当您向用户展示菜单时,您可能需要我所描述的层次结构。但是,当用户向菜单添加项目时,它会以不同的方式呈现 - 您需要他们选择要添加项目的菜单、类别和子类别,然后提供新食品项目的详细信息。我会说这需要不同的模型【参考方案2】:

添加到另一个答案。

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

public class SubCategory : Category

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

尽管您也可以通过允许 Category 具有 null Parent 来消除 SubCategory 类。

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

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

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

【讨论】:

感谢您的回答!非常有帮助。我想知道,我是否需要在子类别中引用食品列表? 菜单 食物项目应该是多对多。我假设 Food item => Category 是 1-many。所以集合导航属性很好。

以上是关于C# Composition - 不完全确定我是不是正确实施的主要内容,如果未能解决你的问题,请参考以下文章

确定组件是不是在 Flex 中完全可见的算法?

F# 在非确定性浮点计算方面是不是受到相同的 C# 警告?

从 C# 调用 C++ 代码而不创建 dll?

C# Dictionary 是不是有可能返回一个完全错误的值。

C# WPF MVVM开发框架Caliburn.Micro Screens, Conductors 和 Composition⑦

不确定数据库连接是不是存在