I am putting together an explanation and code example of this design pattern, attempting to help others around me grasp it (along with helping myself to master the pattern as we
Sorry. That is a quite inflexxible factory. Reflection can giva some POWWAH!!
public interface IFood
{
bool IsTasty { get; }
}
public class Hamburger : IFood
{
public bool IsTasty {get{ return true;}}
}
public class PeaSoup : IFood
{
public bool IsTasty { get { return false; } }
}
public class FoodFactory
{
private Dictionary<string, Type> _foundFoodTypes =
new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Scan all specified assemblies after food.
/// </summary>
public void ScanForFood(params Assembly[] assemblies)
{
var foodType = typeof (IFood);
foreach (var assembly in assemblies)
{
foreach (var type in assembly.GetTypes())
{
if (!foodType.IsAssignableFrom(type) || type.IsAbstract || type.IsInterface)
continue;
_foundFoodTypes.Add(type.Name, type);
}
}
}
/// <summary>
/// Create some food!
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public IFood Create(string name)
{
Type type;
if (!_foundFoodTypes.TryGetValue(name, out type))
throw new ArgumentException("Failed to find food named '" + name + "'.");
return (IFood)Activator.CreateInstance(type);
}
}
Usage:
var factory = new FoodFactory();
factory.ScanForFood(Assembly.GetExecutingAssembly());
Console.WriteLine("Is a hamburger tasty? " + factory.Create("Hamburger").IsTasty);
Edit, feedback on your code:
First of all, factories are used to be able to create objects with a little code changes as possible when adding new types of implementations. Using an enum means that all places that are invoking the factory need to use an enum and be updated when the enum changes.
Sure, it's still a bit better than creating types directly.
The second problem with your code is that you are using a switch statement (but that's the best way to do it if the enum is an requirement). It's better to be able to register all different classes in some way. Either from a config file or by allowing the actual implementations (for instance the Hamburger class) to register themselves. This requires that the factory follows the singleton pattern.
Here comes Reflection to the rescue. Reflection allows you to go through all types in DLLs and EXEs. So we can search for all classes that implements our interface and therefore be able to build a dictionary will all classes.
I think your explanation including the real world example is good. However, I don't think your example code shows the real benefits of the pattern.
Some possible changes:
I would suggest you use interfaces instead of abstract classes/inheritance. Other than that, it looks OK.