Salt cannot sensibly offer the modified taste on its own : it needs an actual other ingredient to salt. But which of the other ingredients ? In fact, what has a "something, but salty" taste is not the Salt, but a salty preparation, which contains another ingredient. This can be modeled in several ways :
Composition
This preparation literally contains the other ingredient, and proxies the call.
class SaltedPreparation : public Ingredient {
Ingredient *baseIngredient;
void Taste() { baseIngredient->Taste(); printf(" but salty"); }
};
Tomato tomato;
SaltedPreparation preparation;
preparation.baseIngredient = &tomato;
preparation.Taste();
Inheritance
A salted tomato is still a tomato, isn't it ? This hinges on the same principle as composition, but the ingredient salts itself. I guess.
class SaltedTomato : public Tomato {
void Taste() { Tomato::Taste(); printf(" but salty"); }
};
SaltedTomato tomato;
tomato.Taste();
Mixin
I'm not keen on writing new classes everytime I need some seasoning, so let's write a template for that ! The Mixin pattern is typical for such generic modifications to existing classes.
template <class BaseIngredient>
class Salted : public BaseIngredient {
void Taste() { BaseIngredient::Taste(); printf(" but salty"); }
};
Salted<Tomato> tomato;
tomato.Taste();
Composite
All of the above models lose the fact that salt is also supposed to be an ingredient on its own. That may be fine, but what if it has to ? Then the Composite pattern may be useful. Let's also distinguish seasonings from main ingredients, because we don't fancy salty salted salt.
class Seasoning : public Ingredient { };
class Salt : public Seasoning {
void Taste() { printf("salty"); }
};
class SeasonedPreparation : public Ingredient {
Ingredient *ingredient;
Seasoning *seasoning;
void Taste() { ingredient->Taste(); printf(", but "); seasoning->Taste(); }
};
Tomato tomato;
Salt salt;
SeasonedPreparation preparation;
preparation.ingredient = &tomato;
preparation.seasoning = &salt;
preparation.Taste();
I'm a bit hungry now.