Abstract Factory Pattern

Definition:

"Creates an instance of several families of classes."

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

Description:

Abstract Factory pattern provides an interface(abstract factory interface) for creating families(NonCommercialMealPlanFactory & CommercialMealPlanFactory) of related objects(WeeklyPlan & MonthlyPlan) without specifying concrete product classes.

Difference between Factory Method Pattern Vs Abstract Factory Pattern?

Factory Method allows to create product object, whereas Abstract Factory allows to create family of related product objects, which shall be used in client application.

What are you achieving with the help of Abstract Factory Pattern?

Able to create family of related objects, and these created objects shall be used in client application to execute product operations.

Abstract Factory Pattern Program:

Abstract Factory Pattern

Aim:

Client application wants to get generated meal plan for different families.

How Abstract Factory Pattern Implemented in Meal Plan application ?

Non-Commercial and Commercial meal plan factories are considered as different families. Both Non-Commercial and Commercial meal plans shall have plan types like weekly plan and monthly plan(concrete products). Each families shall create objects for different plan types and these created objects are used in client application for executing product methods.

MealPlan(Abstract Product) : declared abstract GenerateMealPlan method, responsible for generating meal plans.

WeeklyPlan & MonthlyPlan(Concrete Products) : classes implements MealPlan abstract class

AbstractMealPlanFactory(Abstract Factory) : declared GetWeeklyMealPlanInstance & GetMonthlyMealPlanInstance abstract methods in AbstractMealPlanFactory abstract class, responsible for creating product objects.

NonCommercialMealPlanFactory & CommercialMealPlanFactory(Concrete Factory) : concrete factory classes implements AbstractMealPlanFactory(abstract factory) class for creating product objects and returning created product objects

AbstractFactoryClientBasic(Client) : Created meal plan factory object(NonCommercialMealPlanFactory & CommercialMealPlanFactory), used for executing GetWeeklyMealPlanInstance & GetMonthlyMealPlanInstance methods, which returns concrete product objects(WeeklyPlan and MonthlyPlan). The concrete product objects(WeeklyPlan and MonthlyPlan) allows to execute product operation(GenerateMealPlan) and get the desired results(generated meal plan).

Conclusion:

Hence, AbstractMealPlanFactory provides an interface for creating families(NonCommercialMealPlanFactory & CommercialMealPlanFactory) of related objects(WeeklyPlan & MonthlyPlan) without specifying their concrete classes.

Example with Abstract Factory Pattern:


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 enum MealPlanFamily
{
    NonCommercial = 1,
    Commercial = 2
}

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

// Abstract Product
public abstract class MealPlan
{
    public abstract List<Meal> GenerateMealPlan(DateTime startDate, DateTime endDate);
}

// Concrete Product 1
public class WeeklyPlan : MealPlan
{
    public override List<Meal> GenerateMealPlan(DateTime startDate, DateTime endDate)
    {
        Console.WriteLine("Generated weekly meal plan");
        return new List<Meal>();
    }
}
    
// Concrete Product 2    
public class MonthlyPlan : MealPlan
{
    public override List<Meal> GenerateMealPlan(DateTime startDate, DateTime endDate)
    {
        Console.WriteLine("Generated monthly meal plan");
        return new List<Meal>();
    }
}
    
// Abstract Factory    
public abstract class AbstractMealPlanFactory
{
    public abstract MealPlan GetWeeklyMealPlanInstance();
    public abstract MealPlan GetMonthlyMealPlanInstance();
}

// Concrete Factory Family 1    
public class NonCommercialMealPlanFactory : AbstractMealPlanFactory
{
    public override MealPlan GetWeeklyMealPlanInstance()
    { 
        return new WeeklyPlan();
    }

    public override MealPlan GetMonthlyMealPlanInstance()
    {
        return new MonthlyPlan();
    }
}
    
// Concrete Factory Family 2    
public class CommercialMealPlanFactory : AbstractMealPlanFactory
{
    public override MealPlan GetWeeklyMealPlanInstance()
    {
        return new WeeklyPlan();
    }

    public override MealPlan GetMonthlyMealPlanInstance()
    {
        return new MonthlyPlan();
    }
}

class AbstractFactoryClientBasic
{
    static void Main(string[] args)
    {
        AbstractMealPlanFactory abstractMealPlanFactory = null;
        MealPlanFamily mealPlanFamily = MealPlanFamily.NonCommercial;

        switch (mealPlanFamily)
        {
            case MealPlanFamily.NonCommercial:
                abstractMealPlanFactory = new NonCommercialMealPlanFactory();
                break;

            case MealPlanFamily.Commercial:
                abstractMealPlanFactory = new CommercialMealPlanFactory();
                break;
        }

        MealPlan weeklyPlan = abstractMealPlanFactory.GetWeeklyMealPlanInstance();
        weeklyPlan.GenerateMealPlan(Convert.ToDateTime("11-01-2016"), Convert.ToDateTime("11-07-2016"));

        MealPlan monthlyPlan = abstractMealPlanFactory.GetMonthlyMealPlanInstance();
        monthlyPlan.GenerateMealPlan(Convert.ToDateTime("11-01-2016"), Convert.ToDateTime("11-30-2016"));

        Console.ReadLine();
    }
}