Search code examples
c#oopinheritanceaggregationcomposition

C# Composition - not fully sure I am implementing correctly


So recently I've been learning more about C# OOP - specifically how to work with inheritance, composition and aggregation.

I'm doing this in the context of a practice task which asks to build a ordering API for a restaurant type service. Specifically, the task asks for a Menu. A Menu can be of multiple types, such as a Lunch Menu, Dinner Menu etc. Each Menu then has multiple Categories, such as Starters, Mains, Desserts etc. A category can then belong to multiple menus. Each category then also has subcategories, so for example a Starter can have hot and cold options. Inside a subcategory then has multiple food items inside it, so for hot items(subcategory) in the Starters(category) on the Lunch menu(menu) there can be soup, pizza etc.

From what I understand of the task and OOP, this will require composition rather than inheritance. This is as each Class HAS classes of the other type inside - a Menu HAS categories, category HAS subcategories etc.

So I have built the classes as follows:

The Menu class:

public class Menu
{
    public Menu()
    {}

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

    private long id;

    private string name;
}

The Category 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; }

}

The Subcategory 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; }
}

And lastly the 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; }
}

So what I have done is following examples online - a instance of the superclass inside each subclass is created and passed into the constructor. This means a subclass cannot exist unless the superclass has also been created - a Category requires a Menu, a subcategory requires a category, and a fooditem requires a subcategory.

The questions I have are:

  • The issue I have now is with instantiating a FoodItem. To create a FoodItem, do I need to create a Menu object, then create a Category object and place the Menu object in, create a subcategory and place the Category in and then a FoodItem and place the subcategory in? Would that be correct? Or do I just create a FoodItem and the rest are automatically created? I think the first option is correct but would like to clarify.
  • Is my assumption that Composition is the right way to go here correct? Or is inheritance the better way to go?
  • For completing the task, I need to be able to create FoodItems and post to the API. Assuming my way of doing question 1 is correct, how would I go about creating the superclasses a FoodItem would need?

Any direction is much appreciated.


Solution

  • You've identified that your menu HAS categories, but have implemented it the other way around (in your code, your category HAS a menu). The references are going from the leaf nodes to the parent, instead of the parent containing a collection of references to the items it contains.

    The other thing that I find unusual about what you have posted is that all the members are private. You can expose properties to the outside world, and at some point you are going to need a way to view and present the data contained within a Menu to the user.

    I would rewrite the classes to look more like this:

    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>();
    }
    

    Note that I've used a get for some, and a get/set for others. This is just an assumption, but you don't normally want the id of objects to change. Likewise, initializing the list and keeping it get-only means that users don't have to do a null check every time they work with it.