views:

193

answers:

5

Let's say I have to model the meals of a diner.

A meal can consist of several "components":

  1. (Fries OR rice OR wedges)
  2. AND (One of six different beverages)
  3. AND (One or two out of seven different sauces OR none at all)

Another meal can consist of:

  1. (Salad OR rice)
  2. AND (Garlic OR no garlic)

Further meals can consist of:

  1. Just fries

  2. Just a beverage

  3. Just ...

How can I model this? (UML, entity-relationship, code, ... whatever you can explain best)

Perhaps it helps if you know some tasks I want to perform, so:

  • Allowing the customer to choose a meal first and display all remaining "add-ons".
  • Detecting a meal from a list of components. For example if the customer ordered fries, a sauce and a beverage, it should be possible to detect the meal from the first example.

I've thought about dividing all components into articles and then adding some kind of role mapping to mark "fries" as supplement to "cheeseburger", "schnitzel", "..." but then I wondered, how I could model multiple add-ons, optional add-ons, n-out-of-m add-ons...

I hope you can help me out...

A: 

I assume this will eventually get stored in a database. I suggest to create two tables:

  1. Would store the components (fries, salad, garlic, etc)
  2. Would have: id1, id2, relationship. Relationship being:
    • belongs to
    • goes with

Based on the "belongs to" relationship, you could find if all components belong to a certain meal. Maybe then go and select all components that belong to that meal and suggest the meal if the components selected make up 50% or more of the meal.

Based on the "goes with" relationship, you could suggest add-ons to the meal, or to the components selected.

SorinV
How do I define, for example, that at least on of three components has to go with the meal?
DR
+1  A: 
  1. It seems like an order can consist of either meals, components, or a mix of both, so I would say, have an Order class that has a list of Components and Meals. Meal should either subclass Component, or they should implement the same interface.
  2. A Meal consists of several "slots," which can be filled by some set of Components. Meals should know how many slots they have and what Components can fill them.
  3. The "detecting a Meal from a list of Components" question is tricky. Off the top of my head, the best way I can think of is giving each Meal a method that takes a list of Components and returns true if that Meal can be made from them (or maybe the subset of Components that would make up that Meal). Order would go through the list of Meals it knows about and see if any of them can be made from the Components in the current Order. There may be a better way to do this, though.

Hope this helps!

Amanda S
Thank you for your answer, but as far as I understand under (2.) you seem to just rephrase my original requirement :) Perhaps you can elaborate.
DR
Is there a specific part you're confused about, that I can explain better?
Amanda S
I think Amanda's on the right track. Other things to consider: using an iMeal interface and then concrete "types" of meals, e.g. Lunch implements iMeal but only allows two sides, Dinner implements iMeal and allows for three sides.
matt eisenberg
+1  A: 

Create Component class, and sublcasses (or objects) for all possible types of Components.

Create an abstract Meal class, and subclasses for all possible types of Meals. A Meal can check, whether a certain list of Components matches it (for detecting a meal from a list of components). And a Meal can present to a customer all the choices of components for this meal.

I agree with Amanda that the Meal should be built of the "Slots". Each slot represents one of the Component choices of the Meal, e.g. Fries OR rice OR wedges. A Slot may also model the m-outof-n option.

The Meal class:

class Meal
{
    class MealSlot
    {
        Add(Component);
        bool DoesItMatch(vector<Component> ComponentsVector)
        {
            //Check if this Slot is filled by some element(s)
            // of ComponentsVector 
        }
        PrintSlotOptions();
        vector<Component> Options;

        // for m-of-n option, if multiple items can be chosen in this slot
        int HowManyNeededToFillIt; 
    };

    bool DoesItMatch(vector<Component> ComponentsVector)
    {
        //Check if all Slots are filled by ComponentsVector elements,
        //using Slot::DoesItMatch function
    }
    void PresentChoices()
    {
        for(i=0; i < Slots.size(); i++)
             Slots[i].PrintSlotOptions;
    }
    vector<Slot> Slots;
};

One of Concrete Meals: (Salad OR rice) AND (Garlic OR no garlic)

class MealType2 : public Meal
{
    MealType2()
    {
        Slots[0].Add(Salad);
        Slots[0].Add(Rice);
        Slots[1].Add(Garlic);
        Slots[1].Add(NOTHING);
    }    
};

Create an Order class which will contain a Meal name, and a list of Components. If a Meal is ordered, call Meal.PresentChoices() . And if a list of Components is given, go over all the Meals and call Meal.DoesItMatch .

Igor Oks
How would I model "m-out-of-n components"?
DR
updated the answer, see inside
Igor Oks
A: 

seems like you meal can be almost any collection of food items, so start with one abstract base class (or interface) for a Food. make lots of concrete subclasses, one for each food: coke, tea, steak, chicken, potato, rice, pasta, soup, salad, etc.

make your components interfaces: appetizer, dinner, protein, starch, dessert, drink, etc.

refactor your concrete classes into whatever hierarchy they seem to want to go into as you write code and tests.

sprinkle in the component interfaces where they make sense.

Ray Tayek
+2  A: 

If this is homework, it may not matter... But - if this is going to be used in a real-world app, I would strongly recommend against using concrete classes for each food item ie. Coke class, Salad class, Rice class, etc. as recommended above. This is a sure way to make your application inflexible.

It would be much better to have a food item class and a drink class with a name property or some such..

Imagine having to rebuild your whole application just because there is now a new special or food item... not cool ;).

I think what is missing from the other answers is the idea of a group. Each food item could belong to a group along with other items, or by itself.

Say fries, rice, and wedges belong to group A. Drinks belong to group B. Then you could model a combo as a list of groups - ie. 1 group A item and 1 group B item, or two group A items and1 group B item.

You could also make food items able to belong to multiple groups at the same time... to make the options more flexible.

The db model could get complicated defining all of the relationships, but I think it's necessary.

Perhaps something like this:

group(id, name, desc) - group of like items - entrees, appetizers, drinks... or anything

foodItem(id, name, desc) - represents a single item - fries, rice, etc.

foodItem_group(foodIgem_Id, group_Id) - maps food items to their group - many to many

combo(id, name, desc) - describes a combo

combo_group(combo_Id, group_Id) - maps groups to combos - many to many

I think this would do for representing the basic required model - you may want additional tables to store what the customer actually ordered.. and of course detecting if a customer order matches a combo is left up to your business logic.

markt
I tend to agree. (And it's not homework :) )
DR
added a bit more.. hopefully helpful.
markt