Factory method pattern provides a way for extensibility. It is a creational pattern. Factory Method pattern, is a method that can be used to create one of the Implemented contracts (Instance of a Concrete class) among choices. Usually creational patterns hides the instantiation from the user.
Scenario:
You want to provide choice to your class users in a specific situation. Those choices fulfils the contract in different ways.
Basic Solution For this Scenario:
For example you have a part of code that has to add or multiply two values based on a configuration. You will implement this like
- You will write two methods for Add and Multiply.
- You will ask you user to call you methods based on the configuration.
void Calc(int n1, int n2)
{
char op= GetOpConfig();
int r;
switch(op)
{
case ‘+’:
r=Add(n1, n2);
case ‘*’:
r=Multiply(n1, n2);
}
Display(r);
}
Problem:
User has to change the code when you are implementing new methods like Subtract. User has to add another case to implement this.
void Calc(int n1, int n2)
{
char op= GetOpConfig();
int r;
switch(op)
{
case ‘+’:
r=Add(n1, n2);
case ‘*’:
r=Multiply(n1, n2);
case ‘-’:
r=Subtract(n1, n2);
}
Display(r);
}
So you both has to alter the code when the requirement changes.
Solution:
You can use Factory Method pattern to solve this issue.
- Understand the scenario and bring up a common contract from it (basically with a class, interface or delegate). The common contract should be abstract superset.
- Here what I mean by superset is, it should cover all the requirements.
- Consider you are implementing a negation operation that requires only one operand. As you are making it common, you have to use the second operator in the abstract but leave it ignored during negation implementation.
- Consider you are implementing ternary operation that requires three operators, then the super class should cover all.
- If you have completed the factory method with two operators and you have a new requirement to support ternary operator that is almost a BREAKING CHANGE.
- Implement your different implementations of contract with that superset’s abstract.
- Implement a factory method, that receives a code for a specific instance (which is given to the user in a document) and returns instance of implemented contract based on the received code.
- Document the usage with following details and give it to the user.
- Contract Details such as properties and methods defined in the contract
Factory method parameters and possible values Factory method is implemented.
Implementation:
Ok. Lets implement a sample for the above requirements.
Understanding the scenario
- We are going to provide the users with a way to calculate.
- We want to make it extensible so that new operators can be added later.
Creating Common Contract
- Calculation basically requires two operands
- Calculation will return one result.
- For unary operator, user won’t give second operand. Implemented contract will ignore the second operator.
public abstract class Operation {
public int Num1 { get; set; }
public int Num2 { get; set; }
public int Result { get; set; }
public abstract void Calc();
}
Implementing Contract
- Above contract can be implemented for Add and Multiply as follows
public class Add : Operation {
public override void Calc() {
Result= Num1 + Num2;
}
}public class Multiply : Operation {
public override void Calc() {
Result = Num1 * Num2;
}
}
Implementing Factory Method
- Factory method can be implemented with a single static method as coded below
public class Calculation {
public static Operation GetOperation(char op) {
switch (op) {
case '+': return new Add();
case '*': return new Multiply();
}
return null;
}
}
Using Factory Method
- Calling factory method is easy. It is just like calling regular methods.
var cal = Calculation.GetOperation(op);
cal.Num1 = n1;
cal.Num2 = n2;
cal.Calc();
var ret = cal.Result;
- value for op can be hard coded or from a configuration.
Extending with Factory Method Pattern
- New implementation can be added anytime without affecting the users code.
- Adding a subtract will be easy as mentioned below
public class Subtract : Operation {
public override void Calc() {
Result = Num1 - Num2;
}
}
- Adding a simple case block will be enough in Factory method.
case '-': return new Subtract();
We can implement the same using interfaces or delegates as contracts