Click here to Skip to main content
14,304,886 members

Understanding and Implementing Factory Pattern in C#

Rate this:
5.00 (27 votes)
Please Sign up or sign in to vote.
5.00 (27 votes)
9 Feb 2015CPOL
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#.

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()
    {
        // How to create the doable object here???
        // doable = new B();
        // This seems wrong
    }

    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();
    }
}

// Constructor of A
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)
    {
        // The bank specific API call to make the payment
        Console.WriteLine("Using bank1 to pay for {0}, amount {1}", product.Name, product.Price);
    }
}

public class BankTwo : IPaymentGateway
{
    public void MakePayment(Product product)
    {
        // The bank specific API call to make the payment
        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):

Image 1

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 enums 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:
                // gateway = new PayPal();
                break;
            case PaymentMethod.BILL_DESK:
                // gateway = new BillDesk();
                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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Rahul Rajat Singh
Architect
India India

I Started my Programming career with C++. Later got a chance to develop Windows Form applications using C#. Currently using C#, ASP.NET & ASP.NET MVC to create Information Systems, e-commerce/e-governance Portals and Data driven websites.

My interests involves Programming, Website development and Learning/Teaching subjects related to Computer Science/Information Systems. IMO, C# is the best programming language and I love working with C# and other Microsoft Technologies.

  • Microsoft Certified Technology Specialist (MCTS): Web Applications Development with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Accessing Data with Microsoft .NET Framework 4
  • Microsoft Certified Technology Specialist (MCTS): Windows Communication Foundation Development with Microsoft .NET Framework 4

If you like my articles, please visit my website for more: www.rahulrajatsingh.com[^]

  • Microsoft MVP 2015

Comments and Discussions

 
QuestionReplaced one dependency with another? Pin
oniDino7-Feb-19 5:18
memberoniDino7-Feb-19 5:18 
AnswerRe: Replaced one dependency with another? Pin
freddie200014-Apr-19 13:08
memberfreddie200014-Apr-19 13:08 
QuestionThank You, good article. Pin
Manoj Sharma22-Mar-18 3:48
memberManoj Sharma22-Mar-18 3:48 
QuestionMissing return? Pin
Member 130427776-Mar-17 20:05
memberMember 130427776-Mar-17 20:05 
AnswerRe: Missing return? Pin
_GP17-May-17 14:43
member_GP17-May-17 14:43 
QuestionExcellent Article, What is new payments is must at every place Pin
frikrishna27-Apr-16 18:57
memberfrikrishna27-Apr-16 18:57 
QuestionHi very nice article, second factory should be like this IMHO Pin
AngelBlueSky25-Jan-16 22:40
memberAngelBlueSky25-Jan-16 22:40 
Question5+ Pin
Joezer BH6-Jul-15 18:21
professionalJoezer BH6-Jul-15 18:21 
QuestionErrors in VS 2013 premium Pin
Member 114762492-Jul-15 12:34
memberMember 114762492-Jul-15 12:34 
AnswerRe: Errors in VS 2013 premium Pin
kevinwils8-Oct-15 3:57
memberkevinwils8-Oct-15 3:57 
QuestionProblem in Opening the soln file downloaded Pin
Member 1034444811-Feb-15 1:29
memberMember 1034444811-Feb-15 1:29 
AnswerRe: Problem in Opening the soln file downloaded Pin
Rahul Rajat Singh11-Feb-15 16:48
mvaRahul Rajat Singh11-Feb-15 16:48 
QuestionMy vote of 5! Pin
jediYL10-Feb-15 19:02
professionaljediYL10-Feb-15 19:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Article
Posted 9 Feb 2015

Stats

115.1K views
1.1K downloads
57 bookmarked