I have the below example code. I've created an simple example to illustrate my challenge.
I'm not sure of what pattern this is using as I'm not fully versed on the patterns (but I am eager to learn).
I have a number of items of type IItem. The example are food items.
I have a public interface (IChef) that whose responsibility is to fetch all the ingredients for making a particular item. I've implemented this interface Chef.
I then have an internal interface (IKitchenHelper) for a generic item type defined using a generic type parameter. The internal interfaces responsibility is to prepared the item. If an item requires specialist preparation then I have created a class for that item that implements the IKitchenHelper else there is a GeneralKitchenHelper.
The Chef implementation has a private method, this method needs to fetch the appropriate kitchen helper, call it's GetPreparedItems and build up a list of all items required for the requested item. The private method needs to call itself recursively if the item has subitems.
I'm stuck on how to get the appropriate kitchen helper. I started with a factory class which maintained a list of what kitchen helpers were needed for which types. I then tried to use Activator.CreateInstance to create the appropriate KitchenHelper but I get a cast exception as BeansOnToastSpecialist can't be cast to IKitchenHelper.
I'd like to not have a static class and perhaps use DI but I am ensure how to go about implementing this. I have used DI before in constructor injection, however, using constructor injection won't work in this case I believe as the Chef will require a number of different kitchen helpers.
Any help, advice will be much appreciated.
public enum ItemType
{
Tomatoes,
Toast,
NavyBeans,
BakedBeans,
BeansOnToast
}
public interface IItem
{
ItemType ItemType { get; }
List<IItem> SubItems { get; }
bool IsPrepared { get; set; }
}
public class GeneralItem : IItem
{
public GeneralItem(ItemType itemType)
{
this.ItemType = itemType;
SubItems = new List<IItem>();
}
public ItemType ItemType { get; }
public List<IItem> SubItems { get; }
public bool IsPrepared { get; set; }
}
public class BakedBeans : IItem
{
public BakedBeans()
{
SubItems = new List<IItem>
{
new GeneralItem(ItemType.Tomatoes),
new GeneralItem(ItemType.NavyBeans),
};
}
public ItemType ItemType => ItemType.BakedBeans;
public List<IItem> SubItems { get; }
public bool IsPrepared { get; set; }
}
public class BeansOnToast : IItem
{
public BeansOnToast()
{
SubItems = new List<IItem>
{
new GeneralItem(ItemType.Toast),
new BakedBeans()
};
}
public ItemType ItemType => ItemType.BeansOnToast;
public List<IItem> SubItems { get; }
public bool IsPrepared { get; set; }
}
public interface IChef
{
List<IItem> GetAllIngredients(IItem item);
}
public class Chef : IChef
{
public List<IItem> GetAllIngredients(IItem item)
{
var items = new List<IItem>();
GetIngredients(items, item);
return items;
}
private static void GetIngredients(List<IItem> items, IItem item)
{
//get appropriate kitchen helper for the passed in item
var myHelper = KitchenHelperDictionary.GetAppropriateHelper(item.ItemType);
foreach (var preparedItem in myHelper.GetPreparedItems(item.ItemType))
{
//TODO: (ensure sub items are not already in the list)
items.Add(preparedItem);
if (item.SubItems.Count == 0) continue;
//call method recursively for all the items subitems
foreach (var itemSubItem in item.SubItems)
{
GetIngredients(items, itemSubItem);
}
}
}
}
public static class KitchenHelperDictionary
{
private static Dictionary<ItemType, Type> allKitchenHelpers =
new Dictionary<ItemType, Type>
{
{ItemType.BakedBeans, typeof(BeansSpecialist)},
{ItemType.BeansOnToast, typeof(BeansOnToastSpecialist)},
};
public static IKitchenHelper<IItem> GetAppropriateHelper(ItemType itemType)
{
//if item type is in the dictionary return a kitchen helper of that type
//else return a generalist kitchen helper
}
}
internal interface IKitchenHelper<T> where T : IItem
{
List<T> GetPreparedItems(ItemType itemType);
}
public class GeneralKitchenHelper : IKitchenHelper<IItem>
{
public List<IItem> GetPreparedItems(ItemType itemType)
{
var items = new List<IItem>();
var item = new GeneralItem(itemType) {IsPrepared = true};
items.Add(item);
return items;
}
}
public class BeansSpecialist : IKitchenHelper<BakedBeans>
{
public List<BakedBeans> GetPreparedItems(ItemType itemType)
{
var items = new List<BakedBeans>();
var item = new BakedBeans {IsPrepared = true};
items.Add(item);
return items;
}
}
public class BeansOnToastSpecialist : IKitchenHelper<BeansOnToast>
{
public List<BeansOnToast> GetPreparedItems(ItemType itemType)
{
var items = new List<BeansOnToast>();
var item = new BeansOnToast {IsPrepared = true};
items.Add(item);
return items;
}
}