samedi 5 décembre 2015

Designing a food ingredient class in OOP

I want to suggest recipes to my users, so I'm fetching recipes from a JSON source (including their ingredients).

At the moment, ingredients can be fetched from three ways:

  1. 3 tomatoes (no particular unit)
  2. 125ml of milk (volume unit, either metric or imperial)
  3. 500g of pasta (mass unit, either metric or imperial)

Requirements

I want to use a DDD architecture, so a layered architecture.

I need to be able to display the ingredient as-is, like suggested in my bullet list above. The user can choose between a metric or imperial view.

  1. 3 tomatoes
  2. 125ml of milk or 1/2 cup of milk
  3. 55g of pasta or 2 ounces of pasta

My challenge

I'm not sure how to design the class in order to respect encapsulation and to ensure an easy-to-maintain design.

My first idea was to represent units with a Unit class, so my Ingredient class would hold a quantity and a unit. But in some cases, the ingredient is unitless. With this idea in mind, my IngredientPresenter would look like this:

public String present(Ingredient ingredient) {
    if ( ingredient.isUnitless() ) 
        return ingredient.getQuantity() + " " + ingredient.getName();
    else
        return ingredient.getUnit() + " " + ingredient.getName();
}

I'm not convinced with this approach since I could have many different types of units, and so my IngredientPresenter would grow rapidly (and violating OCP).

Then, I thought I could go with polymorphism. While it seems a good approach, I don't know what to expose in my interface since my implementations would be completely different. I would need to expose my methods in implementations, so loosing all the benefits of polymorphism. My IngredientPresenter would look like below:

public String present(Ingredient ingredient) {
    if ( ingredient instanceof UnitlessIngredient ) {
        UnitlessIngredient actualIngredient = (UnitlessIngredient) ingredient;
        return actualIngredient.getQuantity() + " " + actualIngredient.getName();
    } else {
        WithUnitIngredient actualIngredient = (WithUnitIngredient) ingredient;
        return actualIngredient.getUnit() + " " + actualIngredient.getName();
    }
}

Actually, I think my problem is that I don't know how to represent units properly, so I'm looking your help.

Thank you for your time!

Aucun commentaire:

Enregistrer un commentaire