Introduction
In this article, we will try to understand what is Factory Pattern, what are the benefits of this pattern and how we can implement this pattern using C#.
Background
It is almost impossible to have an application that contains only one class. Typically, an application will have many classes involved, each with a dedicated responsibility, to implement the desired functionality. Which would mean that it is inevitable for the classes to communicate with other classes. This can easily be achieved if we let the classes instantiate the classes it needs and then call the methods on these classes.
So if we have a class A
that wants to call a method of class B
, we can simply have an object of B
inside A
and call its methods whenever we need to. The code will look something like the following:
public class B
{
public void DoTaskOne()
{
Console.WriteLine("B.DoSomething");
}
}
public class A
{
private B b;
public A()
{
b = new B();
}
public void GetOneDone()
{
b.DoTaskOne();
}
}
This approach of having the class instances contained inside other classes will work but it has some downsides. The first problem is that each class needs to know about every other class that it wants to use. This will make this application a maintenance nightmare. Also, the above approach will increase the coupling between the classes.
From the best practices' perspective, whenever we are designing our classes, we should keep the dependency inversion principle in mind when it comes to dependency between classes. Dependency Inversion Principle says that the higher level modules should always depend on abstractions rather than lower level modules directly. So we should always design our classes in such a way that they always depend on the interfaces or abstract
classes rather than other concrete classes.
So the classes we saw in the above example will change. We first need to have an interface that A
can use to call DoTaskOne
. Class B
should implement this interface. The new classes will look like the following:
interface IDoable
{
void DoTaskOne();
}
public class B : IDoable
{
public void DoTaskOne()
{
Console.WriteLine("B.DoSomething");
}
}
public class A
{
private IDoable doable;
public A()
{
}
public void GetOneDone()
{
doable.DoTaskOne();
}
}
The above code shows the classes perfectly designed where the higher lever modules depend on abstractions and the lower level modules implement these abstractions. But wait... how are we going to create an object of B
? Should we still do that as we did in the previous code, i.e., doing a new on B
in the A
's constructor? But would it not defeat the whole purpose of having loose coupling?
This is exactly where the Factory pattern will be useful. The Factory completely hides the process of creating objects. Factory pattern totally abstracts the responsibility of creating classes from the client classes. The major benefit of this is that our client code is completely ignorant of creation process of dependent classes. So to instantiate the actual in our above code, we have to do something like the following in the constructor.
public class DoableFactory
{
public B GetConcreteDoable()
{
return new B();
}
}
public A()
{
DoableFactory factory = new DoableFactory();
doable = factory.GetConcreteDoable();
}
This loose coupling is also good from the extensibility perspective. With the factory pattern in place, the client code also has the possibility of using multiple dependent classes as long as these dependent classes adhere to the contract, i.e., implement interface. So in the above example, the client code will simply not be calling the factory method, but will also be providing some information that can be used to identify the concrete object that needs to be created.
Using the Code
The example we saw above was rather contrived. To understand the Factory pattern, let us try to implement a sample application. Let's say we have an eCommerce application and we have 2 payment gateways integrated with our application. Let's call these payment gateways as BankOne
and BankTwo
. The BankOne
charges 2% on credit cards if the order is less that 50 USD and 1% if it is more than 50 USD. BankTwo
on the other hand charges flat 1.5% for all the amounts.
So our payment module presents the user with three options as:
BankOne
BankTwo
- Best for me
Let's start by looking at our Product
model. This product model will represent the product that the user is trying to purchase.
class Product
{
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
}
Now let us look at IPaymentGateway
interface first. This interface will define the contract that all the payment gateways, i.e., banks' classes should conform to.
interface IPaymentGateway
{
void MakePayment(Product product);
}
Note: In the real world, the MakePayment
will also accept user information to identify the user. We are not showing it here to keep the sample free from digression.
Now let's create the classes that will contain the actual code for making the payment by invoking the bank specific API.
public class BankOne : IPaymentGateway
{
public void MakePayment(Product product)
{
Console.WriteLine("Using bank1 to pay for {0}, amount {1}", product.Name, product.Price);
}
}
public class BankTwo : IPaymentGateway
{
public void MakePayment(Product product)
{
Console.WriteLine("Using bank2 to pay for {0}, amount {1}", product.Name, product.Price);
}
}
Now it's time to create our factory class to handle all the gory details of creating these objects. To be able to identify what payment mechanism user has selected, let's define a simple Enum
PaymentMethod
.
enum PaymentMethod
{
BANK_ONE,
BANK_TWO,
BEST_FOR_ME
}
The factory class will use this enum
to identify what payment gateway concrete class should be created. Let's look at our factory class implementation now.
public class PaymentGatewayFactory
{
public virtual IPaymentGateway CreatePaymentGateway(PaymentMethod method, Product product)
{
IPaymentGateway gateway = null;
switch(method)
{
case PaymentMethod.BANK_ONE:
gateway = new BankOne();
break;
case PaymentMethod.BANK_TWO:
gateway = new BankTwo();
break;
case PaymentMethod.BEST_FOR_ME:
if(product.Price < 50)
{
gateway = new BankTwo();
}
else
{
gateway = new BankOne();
}
break;
}
return gateway;
}
}
What our factory class is doing is that it is accepting the user selected payment gateway and then based on the selection, it is creating the concrete payment gateway class. As we can see that it has a lot of logic to decide which payment gateway to select, we have effectively abstracted out all these gory details from the client code. Otherwise, every class that wants to use a payment gateway would have to write all this logic. Let's now look at how the client
class can use this factory method to make the payment.
public class PaymentProcessor
{
IPaymentGateway gateway = null;
public void MakePayment(PaymentMethod method, Product product)
{
PaymentGatewayFactory factory = new PaymentGatewayFactory();
this.gateway = factory.CreatePaymentGateway(method, product);
this.gateway.MakePayment(product);
}
}
Now our client class does not depend on the concrete payment gateway classes. It also does not have to worry about the creation logic of the concrete payment gateway classes. All this is nicely abstracted out in the factory class itself.
The Factory pattern is a very useful pattern when it comes to keeping our client code decoupled from dependent classes. It enables the application to be maintained more easily. It also makes it very easy to extend as new concrete classes can be added without impacting the existing concrete classes and the client code.
Looking at GoF Factory Method
GoF defines factory method as “Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiate to subclasses”. If we look at the class diagram for Factory Method (Reference: GoF Design Patterns):
Let's see what each of these classes represents:
Product
: Defines the interface of objects the factory method creates (IPaymentGateway
) ConcreteProduct
: Implements the Product
interface (BankOne
, BankTwo
) Creator
: Declares the factory method, which returns an object of type Product
(PaymentGatewayFactory
) ConcreteCreator
: Overrides the factory method to return an instance of a ConcreteProduct
Now if we compare our current implementation with the GoF factory method, we have our interface IPaymentGateway
which is interface of objects the factory method creates. We have our BankOne
and BankTwo
classes that are the ConcreteProducts
. As for the factory classes, we are using a single factory class PaymentGatewayFactory
instead of having a hierarchy. But on a closer look, we will see that our factory class is in fact the Creator
class of GoF patterns. The only difference is that instead of being a pure abstract
class, our class comes with some abstract behavior.
So how can we plug in and use ConcreteCreator
with our design. Let's say we want to create more concrete payment gateway classes that will be used by other parts of the application. To do this, we first have to have new enum
s values for the new concrete classes like the following:
enum PaymentMethod
{
BANK_ONE,
BANK_TWO,
BEST_FOR_ME,
PAYPAL,
BILL_DESK
}
Now we can have one factory class derived from our PaymentGatewayFactory
class which will contain the logic for these new payment gateways.
public class PaymentGatewayFactory2 : PaymentGatewayFactory
{
public virtual IPaymentGateway CreatePaymentGateway
(PaymentMethod method, Product product)
{
IPaymentGateway gateway = null;
switch (method)
{
case PaymentMethod.PAYPAL:
break;
case PaymentMethod.BILL_DESK:
break;
default:
base.CreatePaymentGateway(method, product);
break;
}
return gateway;
}
}
Now wherever we want to use the newly added payment mechanism, we just have to create PaymentGatewayFactory2
instead of PaymentGatewayFactory
and all the 5 payment gateway concrete classes will be available to the client code.
public class PaymentProcessor2
{
IPaymentGateway gateway = null;
public void MakePayment(PaymentMethod method, Product product)
{
PaymentGatewayFactory2 factory = new PaymentGatewayFactory2();
this.gateway = factory.CreatePaymentGateway(method, product);
this.gateway.MakePayment(product);
}
}
Now our Creator is not a pure abstract
class but it comes with some default functionality which can be overridden by the concrete factories derived from it.
Conclusion
In this article, we looked at simple factory pattern and the scenarios where factory pattern can be useful. We have implemented a class factory pattern using C#. The article has been written from the beginner's perspective. I hope this has been informative.
History
- 9th February, 2015: First version