Food Calculator Structure

Cags

Contributor
Joined
Feb 19, 2004
Messages
695
Location
Melton Mowbray, England
Hi, I've just started working on an application to help me easily work out nutritional information about the foods I am eating in a day. I've come up with a basic data structure and just wondered if anybody had any input on the solution I have currently come up with.
C#:
public struct Nutrition {		
	public int Fat, Protein, Carbs, Calories;

	public Nutrition(int myFat, int myProtein, int myCarbs, int myCalories) 
	{
		Fat = myFat;
		Protein = myProtein;
		Carbs = myCarbs;
		Calories = myCalories;
	}
}

public class Consumable {
	private Nutrition _nutritionInfo;
	private string _name;

	public Nutrition NutritionInfo {
		get { return _nutritionInfo; }
	}

	public string Name {
		get { return _name; }
	}

	public Consumable(Nutrition pNutritionInfo, string pName) {
		_nutritionInfo = pNutritionInfo; // per 100g
		_name = pName;
	}
}

public class Ingredient {
	private Consumable _foodType;
	private int _amount;

	public Consumable FoodType {
		get { return _foodType; }
	}

	public int Amount {
		get { return _amount; }
	}

	public Ingredient(Consumable pFoodType, int pAmount) {
		_foodType = pFoodType;
		_amount = pAmount;
	}

	public Nutrition GetNutritionalInfo() {
		int fat = (FoodType.NutritionInfo.Fat / 100) * Amount;
		int carbs = (FoodType.NutritionInfo.Carbs / 100) * Amount;
		int protein = (FoodType.NutritionInfo.Protein / 100) * Amount;
		int calories = (FoodType.NutritionInfo.Calories / 100) * Amount;

		return new Nutrition(fat, protein, carbs, calories);
	}
}

public class Recipe {
	private ArrayList _myIngredients; // will be converted to typed array
	private string _name;

	public ArrayList Ingredients {
		get { return _myIngredients; }
		set { _myIngredients = value; }
	}

	public string Name {
		get { return _name; }
		set { _name = value; }
	}

	public Recipe(string pName) {
		_myIngredients = new ArrayList();
		_name = pName;
	}

	public Nutrition GetNutritionalInfo() {
		
		int fat = 0, carbs = 0, protein = 0, calories = 0;

		for(int i = 0; i < _myIngredients.Count; i++) {
			fat += ((Ingredient)_myIngredients[i]).FoodType.NutritionInfo.Fat;
			carbs += ((Ingredient)_myIngredients[i]).FoodType.NutritionInfo.Carbs;
			protein += ((Ingredient)_myIngredients[i]).FoodType.NutritionInfo.Protein;
			calories += ((Ingredient)_myIngredients[i]).FoodType.NutritionInfo.Calories;
		}

		return new Nutrition(fat, protein, carbs, calories);
	}
}
The application will store collections of Consumable's and Recipe's (in either xml or database, i'll cross that bridge when I come to it). Then the user can easily create a list of what they have eaten in a day and the application will generate a list of how many calories it was etc.
 
Overall this looks pretty good. I have just a few questions...

Why not make Nutrition a class also?

Have you thought about using a strongly typed collection implemented using the CollectionBase class instead of an ArrayList for the Recipe class? You might even want to think about having the recipe class inherit from CollectionBase instead of have a private ArrayList.

Should Ingredient inherit consumable?
 
I thought about making Nutrition a class, but since there weren't going to be any methods, only a few pieces of data I decided on a struct. I'm not sure if this was a good decision or not, but thats why it's a struct. I did consider making the Recipe class inherit from collection base and was infact torn between doing this and replacing the arraylist with a private strongly typed array. In the end I used the arraylist with the intention of replacing it, purely because I could remember how todo it off of the top of my head. Wheras I wasn't completely confident I would be able to Inherit from CollectionBase without looking up an example.

I was also originally considering allowing a Recipe to contain other Recipes rather than just Ingredients (probably using some kind of Interface to allow casting) but I couldn't see any real reason todo this as the Ingredients from the Recipe could just be added seperately anyway.

The only real difference between the classes Consumable and Ingredient is that an Ingredient is a quantative amount of a Consumable, whereas a Consumable contains only the Nutritional value of 100g. So I don't believe Inheritance would help.

For example if the Recipe was a cheese sandwich it would look something like...
C#:
// NB. Hope this is right, I haven't tried it in VS. Obviously the Consumables
// would be coming from a collection not just declared in a method like this.
Consumable Cheese = new Consumable(new Nutrition(int, int, int, int), "Cheese");
Consumable Bread = new Consumable(new Nutrition(int, int, int, int), "Bread");
Consumable Margerine = new Consumable(new Nutrition(int, int, int, int), "Margerine");

Recipe myRecipe = new Recipe("Cheese Sarnie");
myRecipe.Ingredients.Add(new Ingredient(Bread, 95g));
myRecipe.Ingredients.Add(new Ingredient(Cheese, 40g));
myRecipe.Ingredients.Add(new Ingredient(Margerine, 5g));
I seperated the Consumable class from the Ingredient class purely so the application will store lots of Consumables, wheras an Ingredient is only created when added to a Recipe.
 
my opinion is that a class with private data members and properties is always better in the long run. Say you move to a database, or end up calculating someting like % daily value or something? With a struct you'll have a lot of refactoring to do. with a class, you'll just need to add what you need and continue on as normal.

I could see it going either way for the Recipe class. I would probably inherit collectionBase, but that might be just what I am more confortable with.

Put Ingredient through the basic inheritance/member test. True or false:
An Ingredient IS A Consumable.
An Ingredient HAS A Consumable.

From reading what you wrote, to me it seems that an ingedient IS A consumable and it just adds some more information, namely quantity.

All in all, I think that everything will work just fine as you have it. I tend to prefer modeling my structures as closely to the problem domain as I can and it seems like you can take yours a few steps further. I don't know how that will impact what you plan to do with the structures, but that's probably what I would have done with them.
 
mskeel said:
Put Ingredient through the basic inheritance/member test. True or false:
An Ingredient IS A Consumable.
An Ingredient HAS A Consumable.

Thats a very difficult one, because technically, depending on your point of view you could argue that both are true. Looking at it from a real world perspective an Ingredient IS a Consumable with an extra piece of information. But you could also argue that an Ingredient is composed of two components, an amount and a Consumable, in which case an Ingredient HAS a Consumable. Also to complicate things technically a Recipe is also a Consumable (which is one of the reasons i was originally going to use an interface).

This is begining to remind me of being back in 6th form and arguing with the teacher over whether certain relationships should be considered one to many or many to many relationships. :)
 
Back
Top