Take the following classic factory pattern:
public interface IPizza
{
decimal Price { get; }
}
public class HamAndMushroomPizza : IPizza
{
decimal IPizza.Price
{
get
{
return 8.5m;
}
}
}
public abstract class PizzaFactory
{
public abstract IPizza CreatePizza(ItalianPizzaFactory.PizzaType pizzaType);
}
public class ItalianPizzaFactory : PizzaFactory
{
public enum PizzaType
{
HamMushroom,
Deluxe,
Hawaiian
}
public override IPizza CreatePizza(PizzaType pizzaType)
{
switch (pizzaType)
{
case PizzaType.HamMushroom:
return new HamAndMushroomPizza();
case PizzaType.Hawaiian:
return new HawaiianPizza();
default:
throw new ArgumentException("The pizza type " + pizzaType + " is not recognized.");
}
}
}
What if one (or many) of the Concrete Pizzas requires a parameter specific to the concrete implementation at construction. For example, lets say the HamAndMushroom factory requires a parameter called, MushroomType and this parameter would be required to instantiate the object?
You would have to add another CreatePizza() method for that factory class. And that would mean that users of the factory wouldn't be able to create those types of pizzas unless they were specifically using an instance of the HamAndMushroomPizzaFactory class. If they simply have a PizzaFactory reference, they can only call the parameterless version and won't be able to create ham and mushroom pizzas generically.
When parameter count gets very high, I do think factory becomes less handy and redundant since the main point of it to make the creation process kinf of invisible.
Also, when the parameters are 'required', then I also think Builder loses its charm.
In this case, I may want to combine factory with a 'Parameter Object' which would reduce the # of parameters needed to be passed into the static factory methods and that could have made the creation logic more readable and neat than using a Builder. But of course, that parameter object is also needed to be created as well but at least it would be in one, single form across your application.
You can add parameters to the creator method(s) of your factory. However, if the number of parameters is getting higher (for me that would be more than 2-3), and especially if some or all of those parameters are optional with reasonable default values, you may consider turning the factory into a Builder instead.
That may be especially appropriate for pizzas, where you usually have the same crust, just with different (combinations) of toppings. A Builder models very closely the common way of ordering e.g. "a pizza with salami, tomatoes, maize and double cheese". OTOH for "predefined" pizzas you may want to define helper factory methods, e.g.
createMargaritaPizza
orcreateHawaiiPizza
which then internally use the builder to create a pizza with the toppings specific to that kind of pizza.You can try something like this:
IMHO concept of factory with implementation specific parameters looks wrong.
You can use reflection:
You could pass a new parameter, such as a Map. And query the properties on each concrete constructor. Then all the methods would have the same signature. However, with this solution, the caller of the constructor has to know the specific properties of the concret constructor...(Coupling)