C# 保存餐厅菜单的合适数据结构

C# 保存餐厅菜单的合适数据结构,c#,oop,data-structures,C#,Oop,Data Structures,我必须实现一个类(用C#,但我认为这并不重要)来保存餐厅菜单的菜单项列表。有两个要求: 每个项目可能都有一个类别,然后将使用该类别输出此项目。例如,所有“饮料”类物品应在“饮料”标签下输出 项目可能是顶级的,即没有类别。输出这些项目时,上面不应有任何标签或带有特定标签 此类的用户应该能够轻松添加项目,如果项目有类别,则指定其类别 我当前的解决方案非常脏,它要求类的用户提供一个类别,不管该项是否有。也就是说,当项目没有任何类别时,用户必须创建某种默认类别 public class Menu {

我必须实现一个类(用C#,但我认为这并不重要)来保存餐厅菜单的菜单项列表。有两个要求:

每个项目可能都有一个类别,然后将使用该类别输出此项目。例如,所有“饮料”类物品应在“饮料”标签下输出

项目可能是顶级的,即没有类别。输出这些项目时,上面不应有任何标签或带有特定标签

此类的用户应该能够轻松添加项目,如果项目有类别,则指定其类别

我当前的解决方案非常脏,它要求类的用户提供一个类别,不管该项是否有。也就是说,当项目没有任何类别时,用户必须创建某种默认类别

public class Menu
{
    public ICollection<Category> Categories { get; set; }
}

public class Category
{
    public string Name { get; set; }
    public ICollection<MenuItem> Items { get; set; }
}

public class MenuItem
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public Category Category { get; set; }
}
公共类菜单
{
公共ICollection类别{get;set;}
}
公共类类别
{
公共字符串名称{get;set;}
公共ICollection项{get;set;}
}
公共类菜单项
{
公共字符串名称{get;set;}
公共十进制价格{get;set;}
公共类别{get;set;}
}
什么样的数据结构/类设计能更好地解决这个问题

编辑:

它应该以某种方式打印出来。更准确地说,这是订购系统中的菜单模型,也可能以文本形式出现。该模型从解析器中获取,然后表示给用户,以便用户可以手动编辑它。 例如,用户可能会在菜单字段中写入类似的内容

项目1{22}

项目2{33}

--类别1--

项目3{44}

然后将其转换回菜单,然后,当提交菜单时,以一种奇特的方式输出给最终用户

更新结构:

经过一些考虑,我想出了这个设计:

public abstract class MenuItem 
{
    public string Name { get; set; }
    public abstract bool IsCategory();
    public abstract decimal Price();
    public abstract ICollection<MenuItem> Items();
}

public class Dish : MenuItem
{
    private readonly decimal price;

    public Dish(decimal price)
    {
        this.price = price;
    }

    public override bool IsCategory()
    {
        return false;
    }

    public override decimal Price()
    {
        return price;
    }

    public override ICollection<MenuItem> Items()
    {
        return new List<MenuItem>(); //or null
    }
}

public class Category : MenuItem
{
    public ICollection<MenuItem> Items { get; private set; }

    public Category() : this(new List<MenuItem>()) {    }

    public Category(ICollection<MenuItem> items)
    {
        this.Items = items;
    }

    public override bool IsCategory()
    {
        return true;
    }

    public override decimal Price()
    {
        return 0; //or make price nullable and return null
    }

    public override ICollection<MenuItem> Items()
    {
        return Items;
    }
}
公共抽象类菜单项
{
公共字符串名称{get;set;}
公共抽象类();
公开摘要十进制价格();
公共摘要i收集项目();
}
公共类菜肴:MenuItem
{
私有只读十进制价格;
公共菜(十进制价格)
{
这个价格=价格;
}
公共覆盖布尔分类()
{
返回false;
}
公共覆盖十进制价格()
{
退货价格;
}
公共覆盖ICollection项()
{
返回新列表();//或null
}
}
公共类类别:MenuItem
{
公共ICollection项{get;private set;}
公共类别():此(新列表()){}
公共类别(i收集项目)
{
这个。项目=项目;
}
公共覆盖布尔分类()
{
返回true;
}
公共覆盖十进制价格()
{
返回0;//或使价格为null并返回null
}
公共覆盖ICollection项()
{
退货项目;
}
}

“菜单”中有一个菜单项列表。

这个问题可能有点过于宽泛,因为我脑子里突然出现了几个问题。例如,副订单可以列在几个地方吗?它们是不同的菜单项,还是你想把菜单项提到几个地方,这样,如果你改变一道主菜的额外土豆价格,那么所有这些额外的东西都会改变,还是只改变你改变的那一个?你需要描述吗?本地化描述如何(例如,如果你是一家意大利餐厅,你可能想发布意大利命名菜肴,但也要有英文描述或名称)。换句话说,这个问题可能更多地是关于需求的讨论,而不是它们的实际实现。我想说的是,对于一个基本菜单,您现有的代码,减去集合属性设置器,乍一看对我来说似乎很好。我建议您选择一个您应该表示的菜单的实际物理副本,或者至少是一个非常类似的副本,然后找出如何表示所有内容。例如,这是用来打印菜单的东西吗?或者只是在订购系统中处理它们?我建议实现两个类,实现一个公共接口
IMenu
,其中第一个类是“顶级”项,第二个类定义一个子级项。我想到的另一种可能性是将
类别设置为NULL,这表示某个项目是顶级项目。在op post中添加了一个答案。