Introduction
Factory pattern is the most widely used pattern in the software engineering world. This pattern introduces loose coupling between classes which is the most important principle one should consider and apply while designing the application architecture. Loose coupling can be introduced in application architecture by programming against abstract
entities rather than concrete implementations. This not only makes our architecture more flexible but also less fragile.
Think Coupling When Using NEW
When you are using “new
” keyword in .NET or Java and/or newObj
in other languages, you are not just creating an object but under the hood you are also introducing coupling within your application. It doesn’t mean you don’t have to use it anymore as it’s the only way of instantiating an object, but we should find a way to do it more effectively because we have to cater to an important factor in software engineering (or even in life which remains constant) and that’s “CHANGE”. Let’s have a look at an example:
VB
Dim myBat As New HardBallBat()
C#
Bat myBat = new HardBallBat();
And we most often extend this approach when we have a set of related classes, e.g.
VB
If (hardball)
Dim myBat As Bat = New HardBallBat()
ElseIf (tapeball)
Dim myBat As Bat = New TapeBallBat()
ElseIf (plasticball)
Dim myBat As Bat = New PlasticBallBat()
C#
if (hardball)
Bat myHardBallBat = new HardBallBat();
else if (tapeball)
Bat myTapeBallBat = new TapeBallBat();
else if (plasticball)
Bat myPlasticBallBat = new PlasticBallBat();
Here, we are instantiating several concrete implementations depending on the condition evaluated at runtime. So, what’s wrong with this approach? There might be dozens of classes which you may add in the future and can also remove some which are of no use to you which shows that this code is not closed for modification, you have to reopen it and do the modification but a good architecture should follow a principle, i.e., the design should be opened for extension but closed for modification. And this sort of code may also be scattered everywhere in your application which can be a maintenance nightmare.
Separate the Aspects that Vary
Now let’s extend the example provided above and consider there is a shop down the road which is selling top quality bats and you have been assigned the task to develop an application for that shop, you might end up writing code something like this in its OrderBat()
method:
VB
Public Function OrderBat() As Bat
Dim myBat As New Bat()
myBat.clean()
myBat.applyGrip()
myBat.applyLogo()
myBat.applyCover()
myBat.pack()
Return myBat
End Function
C#
public Bat OrderBat()
{
Bat myBat = new Bat();
myBat.clean();
myBat.applyGrip();
myBat.applyLogo();
myBat.applyCover();
myBat.pack();
return myBat;
}
And an extended version of this example might be having a condition evaluated at runtime according to customer’s choice of the bat he/she wants to buy and every concrete implementation extends the base class which is “Bat
”. Therefore:
VB
Private Function OrderBat(ByVal choice As String) As Bat
Dim myBat As Bat
Select Case choice
Case "hardball"
myBat = New HardBallBat()
Case "softball"
myBat = New SoftBallBat()
Case "plasticball"
myBat = New PlasticBallBat()
End Select
myBat.clean()
myBat.applyGrip()
myBat.applyLogo()
myBat.applyCover()
myBat.pack()
Return myBat
End Function
C#
private Bat OrderBat(string choice)
{
Bat myBat = default(Bat);
switch (choice)
{
case "hardball":
myBat = new HardBallBat();
break;
case "softball":
myBat = new SoftBallBat();
break;
case "plasticball":
myBat = new PlasticBallBat();
break;
}
myBat.clean();
myBat.applyGrip();
myBat.applyLogo();
myBat.applyCover();
myBat.pack();
return myBat;
}
Now you might have analyzed that this method is not closed for modification because if in the future they decided to sell any new bat or want to remove something from their collection, you have to again reopen it and do the modification but you might have also analyzed there are certain other parts in the method that don’t need to be changed or at least don’t have any chance of change in the future, i.e.
myBat.clean()
myBat.applyGrip()
myBat.applyLogo()
myBat.applyCover()
myBat.pack()
Then why not separate those aspects of code that change so that we just have to worry about that part of our code, i.e.:
VB
Select Case choice
Case "hardball"
myBat = New HardBallBat()
Case "softball"
myBat = New SoftBallBat()
Case "plasticball"
myBat = New PlasticBallBat()
End Select
C#
switch (choice)
{
case "hardball":
myBat = new HardBallBat();
break;
case "softball":
myBat = new SoftBallBat();
break;
case "plasticball":
myBat = new PlasticBallBat();
break;
}
As we are now aware what is changing in our code and what isn’t, we can now encapsulate it. But wait! The code that is varying as we can see contains the object creation logic and we want to isolate it from our client so in which method we should put it? That’s right, Factory method! Because any method that deals with the object creation can be called as factory method.
Simple Bat Factory
Our client will use this factory to get the object it wants and beauty of this pattern is that it doesn’t let client to change its code to get the thing it wants, the client just has to demand from the factory for the object it needs, as this is what factory is for so let's define a simple Bat
factory:
VB
Public MustInherit Class BatFactory
MustOverride Function CreateBat(ByVal choice As String) As Bat
End Class
C#
public abstract class BatFactory
{
public abstract Bat CreateBat(string choice);
}
This is our base factory class which must be implemented by all the factories that want to supply us bats because this is what our client recognizes and can only work with. So let’s define it:
VB
Public Class SimpleBatFactory
Inherits BatFactory
Overrides Function CreateBat(ByVal choice As String) As Bat
Dim myBat As Bat
Select Case choice
Case "hardball"
myBat = New HardBallBat()
Case "softball"
myBat = New SoftBallBat()
Case "plasticball"
myBat = New PlasticBallBat()
End Select
Return myBat
End Function
End Class
C#
public class SimpleBatFactory : BatFactory
{
public override Bat CreateBat(string choice)
{
Bat myBat = default(Bat);
switch (choice)
{
case "hardball":
myBat = new HardBallBat();
break;
case "softball":
myBat = new SoftBallBat();
break;
case "plasticball":
myBat = new PlasticBallBat();
break;
}
return myBat;
}
}
Now our client will simply use the CreateBat
method to get the bat of customer’s choice provided the returned object implements the required interface. We can now modify the client code and this would be the last modification to our client class, i.e.
VB
Public Function OrderBat(ByVal choice As String) As Bat
Dim myBat As Bat = _factory.CreateBat(choice)
myBat.clean()
myBat.applyGrip()
myBat.applyLogo()
myBat.applyCover()
myBat.pack()
Return myBat
End Function
C#
public Bat OrderBat(string choice)
{
Bat myBat = _factory.CreateBat(choice);
myBat.clean();
myBat.applyGrip();
myBat.applyLogo();
myBat.applyCover();
myBat.pack();
return myBat;
}
Our Order Bat
method is now delegating object creation responsibility to our factory method. Putting it all together, the client class will certainly look like:
VB
Public Class SuperShop
Dim _factory As BatFactory
Public Sub New(ByVal factory As BatFactory)
Me._factory = factory
End Sub
Public Function OrderBat(ByVal choice As String) As Bat
Dim myBat As Bat = _factory.CreateBat(choice)
myBat.clean()
myBat.applyGrip()
myBat.applyLogo()
myBat.applyCover()
myBat.pack()
Return myBat
End Function
End Class
C#
public class SuperShop
{
BatFactory _factory;
public SuperShop(BatFactory factory)
{
this._factory = factory;
}
public Bat OrderBat(string choice)
{
Bat myBat = _factory.CreateBat(choice);
myBat.clean();
myBat.applyGrip();
myBat.applyLogo();
myBat.applyCover();
myBat.pack();
return myBat;
}
}
Now while instantiating the object of SuperShop
, we just have to pass it the reference of the factory we want to get our bats from, e.g.:
VB
Dim factory As New SimpleBatFactory()
Dim shop As New SuperShop(factory)
shop.OrderBat("hardball")
C#
SimpleBatFactory factory = new SimpleBatFactory();
SuperShop shop = new SuperShop(factory);
shop.OrderBat("hardball");
Client doesn’t need to worry about the object instantiation logic as it has now been taken care by our factory.
Loose Coupling and Flexibility
Another important thing to note here is despite the fact that we have effectively isolated the code from the client class and now our maintenance is in one place but it also introduces flexibility and loose coupling in our architecture. If, for example, in the future SuperShop decided to take bats from other manufacturer rather than form SimpleBatFactory
what we just have to do is pass the instance of that factory, Simple and neat? For example:
VB
Public Class CABatFactory
Inherits BatFactory
Overrides Function CreateBat(ByVal choice As String) As Bat
Dim myBat As Bat
Select Case choice
Case "hardball"
myBat = New CAHardBallBat()
Case "softball"
myBat = New CASoftBallBat()
Case "plasticball"
myBat = New CAPlasticBallBat()
End Select
Return myBat
End Function
End Class
C#
public class CABatFactory : BatFactory
{
public override Bat CreateBat(string choice)
{
Bat myBat = default(Bat);
switch (choice) {
case "hardball":
myBat = new CAHardBallBat();
break;
case "softball":
myBat = new CASoftBallBat();
break;
case "plasticball":
myBat = new CAPlasticBallBat();
break;
}
return myBat;
}
}
This is the factory that will now provide us with the bats from our preferred manufacturer and our object instantiation will now use this factory instead:
VB
Dim factory As New CABatFactory()
Dim shop As New SuperShop(factory)
shop.OrderBat("hardball")
C#
CABatFactory factory = new CABatFactory();
SuperShop shop = new SuperShop(factory);
shop.OrderBat("hardball");
As you can see, we haven’t changed the client’s code at all, and now the client is able to work with the objects returned by the factory of our choice.
More Control
One approach to factory pattern have been described above but what if you want to have more control over how the object can be instantiated and only the things you want, would be open for modification by third parties? Let’s say the SuperShop wants to have franchises everywhere in the country but they want to have some quality control also so that the franchisees may take bats from their preferred suppliers but the other quality measures cannot be altered in any way! Don’t you think they are really in need of a framework here to easily manage all of the requirements of their franchisee?
A Framework for BatFactory
SuperShop can provide this Framework to their franchisees so that they can implement the object creation logic by themselves but still can have the power to manage and enforce their quality measures. Let’s look at the altered version of our BatFactory
Class.
VB
Public MustInherit Class BatFactory
Public Function OrderBat(ByVal choice As String) As Bat
Dim myBat As Bat = Me.CreateBat(choice)
myBat.clean()
myBat.applyGrip()
myBat.applyLogo()
myBat.applyCover()
myBat.pack()
Return myBat
End Function
MustOverride Function CreateBat(ByVal choice As String) As Bat
End Class
C#
public abstract class BatFactory
{
public Bat OrderBat(string choice)
{
Bat myBat = this.CreateBat(choice);
myBat.clean();
myBat.applyGrip();
myBat.applyLogo();
myBat.applyCover();
myBat.pack();
return myBat;
}
public abstract Bat CreateBat(string choice);
}
So, what we have done here? We have just included the factory method inside our base class (an abstraction) that will delegate the responsibility of object creation to its derived classes. Now the implementers of this class can’t change any of our quality measures because we have just localized them and on the other hand can freely provide their own object instantiation logic by overriding the CreateBat()
function. OrderBat
function is not really interested in how the objects are created provided the returned type implemented the interface required.
Wait There’s More
Before concluding this article, why not let one our franchisee implement our framework and see how they will actually use it?
VB
Public Class SuperShopFranchisee
Inherits BatFactory
Overrides Function CreateBat(ByVal choice As String) As Bat
Dim myBat As Bat
Select Case choice
Case "hardball"
myBat = New AddidassHardBallBat()
Case "softball"
myBat = New AddidassSoftBallBat()
Case "plasticball"
myBat = New AddidassPlasticBallBat()
End Select
Return myBat
End Function
End Class
C#
public class SuperShopFranchisee : BatFactory
{
public override Bat CreateBat(string choice)
{
Bat myBat = default(Bat);
switch (choice)
{
case "hardball":
myBat = new AddidassHardBallBat();
break;
case "softball":
myBat = new AddidassSoftBallBat();
break;
case "plasticball":
myBat = new AddidassPlasticBallBat();
break;
}
return myBat;
}
}
As you can see, our franchisee have successfully provided its own implementation, now they just have to instantiate the object of their shop and they are good to go:
VB
Dim franchisee As New SuperShopFranchisee
franchisee.OrderBat("hardball")
C#
SuperShopFranchisee franchisee = new SuperShopFranchisee();
franchisee.OrderBat("hardball");
OrderBat
will confirm that all of quality measures of franchiser have been followed and delegate the object creation responsibility to the factory method implemented by our franchisee to get the object as OrderBat
only concerned with the object it needs not the creation logic because this is what factory method is for.
Some Theory
Now I think we are in a position to understand what the official definition actually said about this pattern after all, as understanding the pattern from the definition first is quite difficult for me at least, because design pattern are more of a practical kind of thing. So, here we go:
“The Factory Method Pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.”
And now miraculously this definition started making sense to me!
Conclusion
One should keep in mind the efforts which have already been done on the problem which one is facing. It's like not to reinvent the wheel and to learn from others' experiences!
References
History
- 27th March, 2010: Initial post
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.