Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Learning Factory Pattern using C#

4.94/5 (29 votes)
21 Feb 2016CPOL3 min read 38.7K   313  
Explaining Factory Pattern in C# using a simple LoggerFactory

Introduction

Factory pattern is very common in programming. If you check .NET Framework or any other frameworks, Factory Pattern is widely used which shows its popularity. Factory Pattern belongs to Creational Patterns, and it deals with object creation. In this article, we shall try to learn Factory Pattern using a simple C# console application.

Background

When we write code, we come across situations like creating objects based on some if conditions or switch case. If this object creation is not based on a proven design pattern, then we are really making the object creation complex and future enhancements very tough. At this time, we should consider Factory Pattern to abstract the complexity of the object creation logic, and enabling future additions hassle free.

Let's take a very simple example of logging functionality in a project. If we had the implementation as below, then adding a new Logging option requires considerable code changes at client code base which is not a good practice.

C#
public void Log(string message, string type)
{
    switch (type)
    {
        case "Database":
            DatabaseLogger databaseLogger =  new DatabaseLogger();
            databaseLogger.Log(message);
            break;
        case "EventViewer":
        default:
            EventViewerLogger eventviewerLogger =  new EventViewerLogger();
            eventviewerLogger.Log(message);
            break;
    }
}

Factory Pattern is nothing but hiding object creation logic from the client so that the end client doesn't have to worry about object creational logic, rather the client can refer to the factory pattern created object using a common interface.

Using the Code

For better understanding, we can create a simple Logger Factory which will help the client to log messages to different options based on their choice.

Factory  Pattern Example in C#

To start with, we need to create an Interface or abstract class as the base class for all classes which we are going to create instance in factory. Here, I have used an Interface ILogger with a method Log message.

C#
 interface ILogger
{
    void Log(string Message);
}

Now, we are going to implement this ILogger in all classes which we wanted to return from Logger Factory. Here, ideally Log method should have the real method to log the message to a file but for demonstrating purposes, I'm just adding a console message.

C#
class FileLogger : ILogger
{
    public void Log(string Message)
    {
        Console.WriteLine("{0} - Logged in File.", Message);
    }
}

the same way implementing ILogger to DatabaseLogger, also Log method definition added.

C#
class DatabaseLogger : ILogger
{
    public void Log(string Message)
    {
        Console.WriteLine("{0} - Logged in Database.", Message);
    }
}

EventViewerLogger also implemented from ILogger and Log method definition added based on the type. We can add new logger classes which are the same as these logger classes.

C#
class EventViewerLogger : ILogger
{
    public void Log(string Message)
    {
        Console.WriteLine("{0} - Logged in EventViewer.", Message);
    }
}

Create an enum to easily identify the LoggerType, In case if we have a new LoggerType, then we can add it here.

C#
enum LoggerType
{
    File,
    Database,
    EventViewer
}

FInally, we have reached the LoggerFactory. Now this factory will take care of the object creation based on the enum values, and will return the created instance back to client code which will be a type of ILogger.

C#
class LoggerFactory
{
    public static ILogger Get(LoggerType type)
    {
        switch (type)
        {
            case LoggerType.Database:
                return new DatabaseLogger();
            case LoggerType.EventViewer:
                return new EventViewerLogger();
            case LoggerType.File:
            default:
                return new FileLogger();
        }
    }
}

If you look at the above code, you can see that the object creation logic is abstracted in the factory and the objects are created based the kind of object requested, as the return type is an Interface ILogger, the client code need not worry about new addition to the factory.

I have written a client code to make use of this factory as below:

C#
static void Main(string[] args)
{
    ILogger logger1 = LoggerFactory.Get(LoggerType.Database);
    logger1.Log("Message from Main");

    ILogger logger2 = LoggerFactory.Get(LoggerType.File);
    logger2.Log("Message from Main");

    ILogger logger3 = LoggerFactory.Get(LoggerType.EventViewer);
    logger3.Log("Message from Main");

    Console.ReadKey();

    /*Output
    Message from Main - Logged in Database.
    Message from Main - Logged in File.
    Message from Main - Logged in EventViewer.
    */
}

In the above code, the client code uses the enum to request a specific object and using that object, the log method is called. Objects are created using ILogger and instantiated using factory. I have given the output below:

Image 2

To explore this sample yourself, you can download the attached code or create a console project named "FactoryPatternSample" and replace the content of Program.cs with the below code block.

Program.cs
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FactoryPatternSample
{
    class Program
    {
        interface ILogger
        {
            void Log(string Message);
        }

        enum LoggerType
        {
            File,
            Database,
            EventViewer
        }

        class FileLogger : ILogger
        {
            public void Log(string Message)
            {
                Console.WriteLine("{0} - Logged in File.", Message);
            }
        }

        class DatabaseLogger : ILogger
        {
            public void Log(string Message)
            {
                Console.WriteLine("{0} - Logged in Database.", Message);
            }
        }

        class EventViewerLogger : ILogger
        {
            public void Log(string Message)
            {
                Console.WriteLine("{0} - Logged in EventViewer.", Message);
            }
        }

        class LoggerFactory
        {
            public static ILogger Get(LoggerType type)
            {
                switch (type)
                {
                    case LoggerType.Database:
                        return new DatabaseLogger();
                    case LoggerType.EventViewer:
                        return new EventViewerLogger();
                    case LoggerType.File:
                    default:
                        return new FileLogger();
                }
            }
        }

        static void Main(string[] args)
        {
            ILogger logger1 = LoggerFactory.Get(LoggerType.Database);
            logger1.Log("Message from Main");

            ILogger logger2 = LoggerFactory.Get(LoggerType.File);
            logger2.Log("Message from Main");

            ILogger logger3 = LoggerFactory.Get(LoggerType.EventViewer);
            logger3.Log("Message from Main");

            Console.ReadKey();

            /*Output
            Message from Main - Logged in Database.
            Message from Main - Logged in File.
            Message from Main - Logged in EventViewer.
            */
        }
    }
}

Summary

In this article, I have explained Factory Pattern with a simple C# application. I hope you have enjoyed this article and got some value addition to your knowledge. Please don't forget to mark your votes, suggestions and feedback to improve the quality of this and upcoming articles.

History

  • 31st January, 2016: Initial version

License

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