Take the following classic factory pattern:
public interface IPizza
{
decimal Price { get; }
}
public class HamAndMushroomPizza : IPizza
{
decimal IP
First of all, it seems strange to me that an abstract class PizzaFactory
contains an abstract general method CreatePizza
that takes a parameter of a more concrete type ItalianPizzaFactory.PizzaType
.
To cover the problem I have just mentioned and the problem stated in the post, I would suggest the following approach.
public struct PizzaDefinition
{
public readonly string Tag;
public readonly string Name;
public readonly string Description;
public PizzaDefinition(string tag, string name, string description)
{
Tag = tag; Name = name; Description = description;
}
}
public abstract class PizzaFactory
{
public abstract IEnumerable GetMenu();
public abstract IPizza CreatePizza(PizzaDefinition pizzaDefinition);
}
public class ItalianPizzaFactory : PizzaFactory
{
public enum PizzaType
{
HamMushroom,
Deluxe,
Hawaiian
}
public override IEnumerable GetMenu()
{
return new PizzaDefinition[] {
new PizzaDefinition("hm:mushroom1,cheese3", "Ham&Mushroom 1", "blabla"),
new PizzaDefinition("hm:mushroom2,cheese1", "Ham&Mushroom 2", "blabla"),
new PizzaDefinition("dx", "Deluxe", "blabla"),
new PizzaDefinition("Hawaian:shrimps,caramel", "Hawaian", "blabla")
};
}
private PizzaType ParseTag(string tag, out object[] options){...}
public override IPizza CreatePizza(PizzaDefinition pizzaDefinition)
{
object[] options;
switch (ParseTag(pizzaDefinition.Tag, out options))
{
case PizzaType.HamMushroom:
return new HamAndMushroomPizza(options);
case PizzaType.Hawaiian:
return new HawaiianPizza();
default:
throw new ArgumentException("The pizza" + pizzaDefinition.Name + " is not on the menu.");
}
}
}
As you see, the ParseTag() method may be of arbitrary complexity, parsing a plain text or an encrypted value. Or the Tag field can be a simple int that is mapped internally to some pizza recipe table, with whole different recipes for even slightly changed pizza content.