Factory Pattern

Definition:

"Factory Pattern facilitates to create an instance of several derived classes."

Factory pattern provides the responsibility of object instantiation to a specific class(Factory class).

Description:

The client application needs to have an instance of specific class(or product) based on input type. Factory pattern allows to create an instance of a specific class(or product) based on client input type. However, the object instantiation process is not exposed to client application and object instantiation process is handled by Factory class. The client application refers to the newly instantiated object through abstract interface(product interface).

What are you achieving with the help of Factory pattern?

  • Factory pattern defines a separate class which is responsible for managing object(product) instantiation.
  • Hide the complexity of creating objects(products) to client application
  • Factory pattern helps to create an instance of a class(a product) and created instance(product) is referred in client application using abstract interface(product interface).
  • Factory pattern provides the abstraction between client application and products that are used in client application.
  • The client application need not to worry about creating an instance of a class( a product) and client application needs to know what type of instance( a product) is needed. If the client application provides the type of instance(a product) to Factory class, then Factory class shall return the requested instance of a class(a product) to client application.

What is the impact if you don’t use Factory pattern ?

  • Object instantiation shall not be in one class and object instantiation process is used in many places in the application. Whenever we need to make any changes in object instantiation like adding new class(product) or removing existing class(product), may need to change the object instantiation process throughout the application.
  • Object instantiation based on client input type introduce the conditional statement and this conditional statement shall be used in many places in the application, instead of keeping the conditional statement in common class.

Program without Factory Pattern:

No Factory Pattern

Abstract Product(MealPlan) : abstract product class defines the signature for generating meal plan.

Concreate Products(WeeklyPlan & MonthlyPlan) : implements abstract product class and generates the meal plan.

Client(NoFactoryClient) : client application class, initialize WeeklyPlan and MonthlyPlan objects and generates the meal plan by invoking GenerateMealPlan method.

        
public enum CuisineType
{
    American = 1,
    Asian = 2,
    European = 3,
    Oceanian = 4
}

public enum MealType
{
    Breakfast = 1,
    Lunch = 2,
    Dinner = 3
}

public enum MealPlanType
{
    Weekly = 1,
    Monthly = 2,
    Custom = 3
}

public class Meal
{
    public int MealId { get; set; }
    public string MealName { get; set; }
    public MealType MealType { get; set; }
    public CuisineType CuisineType { get; set; }
}

public abstract class MealPlan
{
    public abstract List GenerateMealPlan(DateTime startDate, DateTime endDate);
}

public class WeeklyPlan : MealPlan
{
    public override List GenerateMealPlan(DateTime startDate, DateTime endDate)
    {
        Console.WriteLine("Generated weekly meal plan");
        return new List();
    }
}

public class MonthlyPlan : MealPlan
{
    public override List GenerateMealPlan(DateTime startDate, DateTime endDate)
    {
        Console.WriteLine("Generated monthly meal plan");
        return new List();
    }
}

class NoFactoryClient
{
    static void Main(string[] args)
    {
        MealPlan weeklyPlan = new WeeklyPlan();
        weeklyPlan.GenerateMealPlan(Convert.ToDateTime("Jan-01-2017"), Convert.ToDateTime("Jan-07-2017"));

        MealPlan monthlyPlan = new MonthlyPlan();
        monthlyPlan.GenerateMealPlan(Convert.ToDateTime("Jan-01-2017"), Convert.ToDateTime("Jan-31-2017"));

        Console.ReadKey();
    }
}
        

Issue in a program without Factory:

  • Client application class(NoFactoryClient class) needs to be aware of products (WeeklyPlan & MonthlyPlan) objects creation logic and responsible for creating various types of product objects.
  • We need to modify the existing client application code If we want to add a new product or remove existing product. In case, if product creation logic is used in many places in client application, then we need change the existing product creation logic in all those places.

How to fix this issue in a program using Factory Pattern:

Factory Pattern

Abstract Product(MealPlan) : no change as compared to program without factory.

Concreate Products( WeeklyPlan & MonthlyPlan) : no change as compared to program without factory.

Factory(MealPlanFactory) : newly added class as compared to program without factory. This class handles the responsibility of object(product) instantiation process.

Client(FactoryPattern) : client application class, interacts with MealPlanFactory class for getting the instance of WeeklyPlan and MonthlyPlan objects and generates the meal plan by invoking GenerateMealPlan method.

    
public abstract class MealPlan
{
    public abstract List GenerateMealPlan(DateTime startDate, DateTime endDate);
}
        
public class WeeklyPlan : MealPlan
{
    public override List GenerateMealPlan(DateTime startDate, DateTime endDate)
    {
        Console.WriteLine("Generated weekly meal plan");
        return new List();
    }
}
    
public class MonthlyPlan : MealPlan
{
    public override List GenerateMealPlan(DateTime startDate, DateTime endDate)
    {
        Console.WriteLine("Generated monthly meal plan");
        return new List();
    }
}

public class MealPlanFactory
{
    public MealPlan GetMealPlanInstance(MealPlanType planType)
    {
        switch(planType)
        {
            case MealPlanType.Weekly:
                return new WeeklyPlan();                    

            case MealPlanType.Monthly:
                return new MonthlyPlan();
    
            default:
                throw new NotSupportedException();                   
        }
    }
}

class FactoryPattern
{
    static void Main(string[] args)
    {
        MealPlanFactory planFactory = new MealPlanFactory();

        MealPlan mealPlan = planFactory.GetMealPlanInstance(MealPlanType.Weekly);
        mealPlan.GenerateMealPlan(Convert.ToDateTime("Jan-01-2017"), Convert.ToDateTime("Jan-07-2017"));

        mealPlan = planFactory.GetMealPlanInstance(MealPlanType.Monthly);
        mealPlan.GenerateMealPlan(Convert.ToDateTime("Jan-01-2017"), Convert.ToDateTime("Jan-31-2017"));

        Console.ReadKey();
    }
}