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

A Journey to Factory Method Pattern

2.37/5 (9 votes)
12 Oct 2018CPOL11 min read 12.1K   18  
Illustration of factory method pattern among various approaches

Inspiration

When I came across factory method pattern, it seemed easy. Since there was no proven authenticity of any article, I went through many sites, found that everyone was using different ways to implement, which made it confusing.

Lots of questions started coming to my mind, like in which scenarios it has to be used? Is there any fixed piece of code to implement this? What is the difference between factory pattern and factory method pattern, or are they the same? If instantiation of object deferred from UI code to subclass, where exactly instantiation needs to take place - inside factory or inside product?

There has been a lot of confusion among design patterns named FACTORY, someone says factory, and some say simple factory, factory pattern, factory method, factory method design pattern, abstract factory.

So I decided to make all illustrations integrated in one article using the same kind of example so that comparing among different concepts could be simple.

Introduction

This is the second design pattern that falls under the creational design pattern defined1 by "Gang of Four".

This pattern is about deferring the object instantiation to sub class.

There is no "factory pattern" defined by GoF, but many sites (3, 4, 5, 6, 7, 8) confirm its existence, as it's most widely used useful, it was defined by "Garry Woodfine" (2, 3). So here I will try to describe all approaches related to factory method.

Who Should Read this Article?

  1. If you are a novice at all for design patterns.
  2. If you are a novice at factory method pattern.
  3. If you are confused between factory pattern and factory method pattern.
  4. If you have gone through many examples related to factor method, but still confused, because you are not able to map the code with its class diagram.
  5. If you want to know what each class in the pattern does and how.

About the Article

This story compares from the real world scenario to the programming world, so the story keeps on switching between both the languages. Since I tried to map coding language with real life language, you might need to map it by perusing and comparing code with explanation. Sometimes, you may feel if code could be shortened, but again it’s just for the sake of mapping with real world example. Sometimes, you won’t find any change in the same class of two different stages, but it is intentional, so that you can identify where the changes took placed.

Sufficient code comments are provided in-side the code, which describes the purpose of code. Hope you will enjoy the journey.

A Real World Example - Juicer Mixer Grinder

So the story starts from the Kitchen, a place needed by everyone! Since it’s about finding a right solution for everyday kitchen’s problem of mixing product, it’s going to be long. If you want bottoms up in one shot, it’s not the right place.

Index

Stage 1 – Simple Class Without Any Interface

Real World Scenario

Few years ago, hardly did I have a craving for omelet, so I used mix egg with the help of spoon only. So it was all good so far. Was I needed to think more than this, probably not?

Yeah…….sometimes, I also needed to mix purees or pulp, but these things could also have been done with the help of different bigger jar or cup and spoon.

I could have bought a blender, but not sure if it would had been economic for this scenario.

In Programming Terms

So sometimes, it’s good if we (as main class) instantiate an object directly without delegating the responsibility, if it requires once in a while.

Class Diagram

Image 1

Implementation Code

UIClass.cs

C#
using System;

namespace SimpleClass
{
    /// <summary>
    /// This is very first example of class instantiation, 
    /// no inheritance or interface concept being used here.
    /// Observations -
    ///       UI - Main class calling 2 different class for Egg and Pulp  
    ///       Product - EggProduct, PulpProduct
    /// Problem - Whenever a new product is added, separate process need to be added
    /// </summary>
    class UIClass
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Please enter item to blend : Egg or Pulp");
            string strUserInput = Console.ReadLine();
           
            switch (Console.ReadLine())
            {
                case "Egg":
                    // EggCup egg = new EggCup();
                    UseCupForEgg egg = new UseCupForEgg();
                    egg.BlendNMixEgg("EggLiquid");
                    break;
                case "Pulp":
                    UseJarForPulp puree = new UseJarForPulp();
                    puree.MixMangoPulp("MilkShake");
                    break;
            }
 
            Console.ReadKey();
        }
 
        public class UseCupForEgg
        {
            public void BlendNMixEgg(string readyProduct)
            {
                Console.WriteLine(readyProduct + "Egg is mixed");
            }
        }
 
        public class UseJarForPulp
        {
            public void MixMangoPulp(string readyProduct)
            {
                Console.WriteLine(readyProduct + "Mango shake is prepared.");
            }
        }
    }
}

Observation on Stage 1

What I observed was that I always do the same process for mixing similar things, and type of end product is of the same type, so why can I not use the same utensil for both the processes? Can I minimize and improve the things? After all, it’s the same defined process (mixing) is going to be used to get same a type of end product which is LIQUID.

Stage 2 - No Factory But With Defined Interface

Real World Scenario

So now, I had a single JAR being used for BLENDING process to convert Egg or Pulp into LIQUID.

In Programming Terms

Single UI using same process to convert multiple raw product to same abstract product.

Class Diagram

Image 2

Implementation Code

UIClass.cs

C#
using System;
 
/// <summary>
/// This is enhanced version of class instantiation by introducing product interface
/// implementation for reusability and interaction of common functionalities.
/// Observations -  
///     1. Object instantiation of product
///     2. UI - Main class calling 2 different class for Egg and Pulp but calling same methods 
/// What's new here -
///     1. UI - Unified UI(Utencil) calling same method(BlendProduct)
/// Problem -
///     1. Every time UI code need to change while adding a new item
///     2. OCP violation
/// </summary>
namespace NoFactory
{
 
    /// <summary>
    /// This is UI code instantiating product classes
    /// </summary>
    class UIClass
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Please enter item for Mixer : Egg, Pulp");
 
            IMixedProduct endProduct = null;
            switch (Console.ReadLine())
            {
                case "Egg":
                    endProduct = new EggProduct();
                    endProduct.BlendProduct("EggLiquid");
                    break;
                case "Pulp":
                    endProduct = new PureeProduct();
                    endProduct.BlendProduct("MilkShake");
                    break;
            }
            Console.ReadKey();
        }
    }
}

Product.cs

C#
/// <summary>
/// Observations -  
///     1. Products - (Two) EggProduct, PulpProduct
/// What's new here -
///     1. Product - Unified abstract product defines same method to be used by different child products
/// </summary>
 
namespace NoFactory
{
    /// <summary>
    ///  Its an essential function of blender, no matter what kind of product its going to mix
    /// </summary>
    public interface IMixedProduct
    {
        void BlendProduct(string readyProduct);
    }
 
    /// <summary>
    ///  Concrete product egg type inheriting abstract product
    /// </summary>
    public class EggProduct : IMixedProduct
    {
        public void BlendProduct(string readyProduct)
        {
            Console.WriteLine(readyProduct + " is prepared.");
        }
    }
 
    /// <summary>
    ///  Concrete product puree type inheriting abstract product
    /// </summary>
    public class PureeProduct : IMixedProduct
    {
        public void BlendProduct(string readyProduct)
        {
            Console.WriteLine(readyProduct + " is prepared.");
        }
    }   
}

Problem with Stage 2

After some time, I needed to make omelet more frequently and in more quantity for my family. So the demand increased in terms of quantity and frequency, it became more time consuming for me to blend many eggs.

Additionally, I needed to make milk shake as well or mash tomato puree sometimes. So whenever I need to grind another item, either the same utensil needed modification or else, I needed to use a different utensil (aka UI).

Let’s understand through the code.

UIClass.cs

C#
using System;
 
/// <summary>
/// This is enhanced version of class instantiation by introducing product interface
/// implementation for reusability and interaction of common functionalities.
/// Observations -  
///     1. Object instantiation of product
///     2. UI - Main class calling 2 different class for Egg and Pulp but calling same methods 
/// What's new here -
///     1. UI - Unified UI(Utencil) calling same method(BlendProduct)
/// Problem -
///     1. Every time UI code need to change while adding a new item
///     2. OCP violation
/// </summary>
namespace ProblemWithNoFactory
{
    /// <summary>
    /// This is UI code instantiating product classes
    /// </summary>
    class UIClass
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Please enter item for Mixer : Egg, Pulp");
 
            IMixedProduct endProduct = null;
            switch (Console.ReadLine())
            {
                case "Egg":
                    endProduct = new EggProduct();
                    endProduct.BlendProduct("EggLiquid");
                    break;
                case "Pulp":
                    endProduct = new PureeProduct();
                    endProduct.BlendProduct("MilkShake");
                    break;
                // New items to be processed
                case "Sauce":
                    endProduct = new SauceProduct();
                    endProduct.BlendProduct("Sauce");
                    break;
                case "Puree":
                    endProduct = new PulpProduct();
                    endProduct.BlendProduct("Puree");
                    break;
            }
            Console.ReadKey();
        }
    }
}

Product.cs

C#
using System;

/// <summary>
/// Observations -  
///     1. Products - (Four) EggProduct, PulpProduct, SauceProduct, PulpProduct
/// What's new here -
///     1. Product - Unified abstract product defines same method to be used by different child products
/// </summary>
 
namespace ProblemWithNoFactory
{
    /// <summary>
    ///  Its an essential function of blender, no matter what kind of product its going to mix
    /// </summary>
    public interface IMixedProduct
    {
        void BlendProduct(string readyProduct);
    }
 
    /// <summary>
    ///  Concrete product egg type inheriting abstract product
    /// </summary>
    public class EggProduct : IMixedProduct
    {
        public void BlendProduct(string readyProduct)
        {
            Console.WriteLine(readyProduct + " is prepared.");
        }
    }
 
    /// <summary>
    ///  Concrete product puree type inheriting abstract product
    /// </summary>
    public class PureeProduct : IMixedProduct
    {
        public void BlendProduct(string readyProduct)
        {
            Console.WriteLine(readyProduct + " is prepared.");
        }
    }
 
    // New items to be added
    public class SauceProduct : IMixedProduct
    {
        public void BlendProduct(string readyProduct)
        {
            Console.WriteLine(readyProduct + " is prepared.");
        }
    }
 
    public class PulpProduct : IMixedProduct
    {
        public void BlendProduct(string readyProduct)
        {
            Console.WriteLine(readyProduct + " is prepared.");
        }
    }
}

Point to Note Here

Violation of OCP – A class should be open for extension but close for modification, but it’s not here.

Requirement Analysis – (Necessity is the mother of invention)

  1. I needed an equipment, which can blend various semi-liquid items with speed.
  2. Every time, I don’t want to change the blending utensil.
  3. I want output in the same liquid form.

Stage 3 – Simple Factory (Also known as Factory, Factory Pattern, Factory Design Pattern)

Solution (in Real World Scenario)

So I thought of buying a blender, which can help me out with blending more eggs in less time. I could also have it use for mixing any puree to make sauce and mixing mango pulp for milk shake. So it was good for mixing the semi-liquid items only.

In Programming Terms

Here, we are delegating the responsibility of object creation to factory (Blender). And we will modify our example to follow OCP and SRP (Single class for single type of responsibility).

Definitions

"It’s a class which holds a method responsible for creation of object based on input type it receives" (aka semi-liquid -egg, puree, and mango pulp etc. in this example).

In simplest terms, Factory helps to keep all object creation in one place and avoids spreading new key value across the codebase.(3)

It creates objects without exposing the instantiation logic to the client and refers to the newly created object through a common interface. (8)

Points to Note

  • It may or may not have factory interface, but it’s not a mandate.
  • Factory class may or may not have static method, depend how you call factory at UI.

Class Diagram

Image 3

Implementation Code

UIClass.cs

using System;

/// <summary>
/// Observations -
///     1. Object instantiation of product of factory not the products 
/// What's new here -
///     1. UI - Main class calling a factory not 2 different class for Egg and Pulp
///     2. UI code will not be changed, while using new items,
///     but it has to be of same type which is semi-liquid
///     3. Follows - OCP, SRP
/// Problem - Limited to handle one type of item only
/// </summary>
namespace SimpleFactoryPattern
{
    /// <summary>
    /// UI class
    /// </summary>
    class UIClass
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Please enter item for Mixer : Egg, Pulp, Sauce, Puree");
 
            BlenderFactory liquid = new BlenderFactory();
            liquid.GetMixingProduct("SemiLiquid", Console.ReadLine());
 
            Console.ReadKey();
        }
    }
}

Factory.cs

   /// <summary>
    /// A Factory with the responsibility of object instantiation
    /// Observation -
    ///     1. UI code will not be changed, in case product is changed
    ///     2. Single class handling instantiation of child product
    ///     3. Object instantiation of product
    /// </summary>
namespace SimpleFactoryPattern
{ 
    /// <summary>
    /// Single factory handling instantiation of all products of same type
    /// </summary>
    public class BlenderFactory
    {
        public string GetMixingProduct(string inputType, string itemName)
        {
            string readyProduct = null;
            if (inputType == "SemiLiquid")
            {
                switch (itemName)
                {
                    case "Egg":
                        IMixedProduct egg = new MixtureProduct();
                        egg.BlendProduct(itemName);
                        break;
                    case "Pulp":
                        IMixedProduct pulp = new MixtureProduct();
                        pulp.BlendProduct(itemName);
                        break;
                    case "Sauce":
                        IMixedProduct sauce = new MixtureProduct();
                        sauce.BlendProduct(itemName);
                        break;
                    case "Puree":
                        IMixedProduct puree = new MixtureProduct();
                        puree.BlendProduct(itemName);
                        break;
                }
            }
            return readyProduct;
        }
    }
}

Product.cs

/// Observations -  
///     1. Products - (One) MixtureProduct
/// What's new here -
///     1. Product - Unified product implements method defined in interface
/// </summary>
namespace SimpleFactoryPattern
{
    /// <summary>
    ///  Its an essential function of blender, no matter what kind of product its going to mix
    /// </summary>
    public interface IMixedProduct
    {
        void BlendProduct(string readyProduct);
    }
 
    /// <summary>
    /// End product type implementing method defined in interface
    /// </summary>
    public class MixtureProduct : IMixedProduct
    {
        public void BlendProduct(string readyProduct)
        {
            Console.WriteLine(readyProduct + " is mixed.");
        }
    }
}

Problem with Stage 3

All was good so far but one day I was in a rush and needed mashed boiled tomatoes for my curry.

Requirement Analysis – (Desire Never Ends)

So I brainstormed – I can mash boiled potatoes so shall I buy a mixer, may be it's too early, and let me think about a cheaper and economic option first. I compared similar properties of mixer and blender, both have blades & motors and both have functions that are mixing the item and both give similar output like liquid.

Stage 4 – Single Factory with Multiple Type of Responsibility (Not Advisable)

Solution (in Real World Scenario)

So I mashed the tomatoes by hand and then mixed them by blender, and wow it worked, the outcome was not that much refined as needed, but it fulfilled the essential need which was mashed tomatoes.

In Programming Terms

Here, we are calling additional method for BOILED items to prepare it before it can be used with abstract method.

Class Diagram

Image 4

Implementation Code

UIClass.cs

C#
using System;
 
namespace FactoryWithMultipleResponsibility
{
    /// <summary>
    /// Observations -
    ///     1. Object instantiation of factory not the products 
    /// What's new here -
    ///     1. UI - Main class calling factory not 2 classes for liquid and boiled item type
    /// Problem -
    /// 1. UI class with multiple type of responsibility
    /// 2. UI code will be changed, if additional responsibility comes in scope
    /// </summary>
    class UIClass
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Please enter item for Mixer : Liquid, or Boiled for mixing.");
            string itemName = Console.ReadLine();
 
            switch (itemName)
            {
                case "Liquid":
                    BlenderFactory liquid = new BlenderFactory();
                    liquid.GetMixingProduct("SemiLiquid", itemName);
                    //BlenderFactory.GetMixingProduct("SemiLiquid", itemName);
                    break;
                case "Boiled":
                    BlenderFactory mash = new BlenderFactory();
                    mash.GetMixingProduct("Boiled", itemName);
                    //BlenderFactory.GetMixingProduct("SemiLiquid", itemName);
                    break;
            }
 
            Console.ReadKey();
        }
    }
}

Factory.cs

C#
/// <summary>
/// A Factory with the responsibility of object instantiation
/// Observation -
///     1. Factory need to inherit MashedProduct for one of its two input types
/// Problem -
///     1. Breaking SRP - As per concept its breaking SRP - So here you can see, 
///     there are more than 1 reason to change the class
///     Whenever a new type like solid type is added, factory code need to be changed.
/// </summary>
namespace FactoryWithMultipleResponsibility
{
    /// <summary>
    /// Single factory with multiple responsibility
    /// </summary>
    public class BlenderFactory : MashedProduct
    {
        public string GetMixingProduct(string inputType, string itemName)
        {
            string readyProduct = null;
            if (inputType == "SemiLiquid")
            {
                switch (inputType)
                {
                    case "Egg":
                        IMixedProduct egg = new MixtureProduct();
                        egg.BlendProduct(itemName);
                        break;
                    case "Pulp":
                        IMixedProduct puree = new MixtureProduct();
                        puree.BlendProduct(itemName);
                        break;
                }
            }
            if (inputType == "Boiled")
            {
                switch (inputType)
                {                   
                    case "BoiledTomato":
                        // Additional responsibility for mashing boiled items
                        MashedProduct mashTomato = new MashedProduct();
                        mashTomato.MashProduct(itemName);
 
                        IMixedProduct boildedPotato = new MixtureProduct();
                        boildedPotato.BlendProduct(itemName);
                        break;
                    case "BoiledPotato":
                        // Additional responsibility for mashing boiled items
                        MashedProduct mashPotato = new MashedProduct();
                        mashPotato.MashProduct(itemName);
 
                        IMixedProduct boildedTomato = new MixtureProduct();
                        boildedTomato.BlendProduct(itemName);
                        break;
                }
            }
            return readyProduct;
        }
    }  
}

Product.cs

C#
/// <summary>
/// Observations -  
///     1. Products - (Two) MixtureProduct
/// What's new here -
///     1. Product - One additional type of product is added
/// </summary>
namespace FactoryWithMultipleResponsibility
{
    /// <summary>
    ///  Its an essential function of blender, no matter what kind of product its going to mix
    /// </summary>
    public interface IMixedProduct
    {
        void BlendProduct(string readyProduct);
    }
    /// <summary>
    /// Concrete product implementing essential method
    /// </summary>
    public class MixtureProduct : IMixedProduct
    {
        public void BlendProduct(string readyProduct)
        {
            Console.WriteLine(readyProduct + " is mixed.");
        }
    }
 
    /// <summary>
    /// A class for additional function of multiple responsibility
    /// </summary>
    public class MashedProduct
    {
        public void MashProduct(string readyProduct)
        {
            Console.WriteLine(readyProduct + " is mixed.");
        }
    }
  
}

Problem with Stage 4

First, its output was not as desired, as I mashed potato by hand, second it can’t fulfill the need of making juice or grinding vegetables, etc.

In Programming Terms

Sometimes, we try to use the same class for the responsibility which it is not made for, just because it has few similar methods and properties and we want to save time and efforts.

Point to Note

Breaking SOLID SRP rule – Assigning more than one type of responsibility to a class. A class should be having a single reason to change it.

Requirement Analysis

Going excitingly on the way to explore what else usually I need in the kitchen and what can I do with this blender? And hence usually, I also needed to grind vegetables to make smoothies or grains as well to make dough, so why not have another equipment.

Stage 5 –With Multiple Factories - Less Feasible Solution

Solution (in Real World Scenario)

I decided to buy a separate mixer for all other things like solid or semi-solid items, so that I can get the desired output with other items.

In Programming Terms

I decided to delegate different responsibility to separate factories for each type of product to avoid violation of SRP.

Class Diagram

Image 5

Implementation Code

UIClass.cs

C#
using System;

/// <summary>
/// Observations -
///     1. Object instantiation of specific factories depends on input type 
/// What's new here -
///     1. UI - Main class calling specific concrete factories according to input type
/// Problem -
///     1. UI class with multiple type of responsibility
///     2. UI code will be changed, if additional responsibility comes in scope
///     3. Maintaining consistency among factories becomes complicated here
/// </summary>
namespace MultipleFactories
{
    /// <summary>
    /// UI code calling specific factories as per input type
    /// </summary>
    class UIClass
    {
        static void Main(string[] args)
        {
            // Code added for mixing and grinding items
            Console.WriteLine("Please enter item for Mixer : Fruit, Boiled, or Grain");           
            string itemType = Console.ReadLine();
 
            switch (itemType)
            {
                case "Fruit":
                    JuiceFactory juice = new JuiceFactory();
                    juice.GetJuiceProduct(itemType);
                    break;
                case "Boiled":
                    MashingFactory semiLiquid = new MashingFactory();
                    semiLiquid.GetMashProduct(itemType);
                    break;
                case "Grain":
                    GrindingFactory flour = new GrindingFactory();
                    flour.GetGrindedProduct(itemType);
                    break;
            }
 
            Console.ReadKey();
        }
    }
}

Factory.cs

C#
/// <summary>
/// What's New -
///     1.  There are separate factory for all type like juice, boiled, flour
/// Problem -
///     1. There is repetition of code involve in each factory, 
///     and if it require changes, changes need everywhere
/// Object instantiation of product
/// </summary>
namespace MultipleFactories
{
    /// <summary>
    /// Concrete juice factory calling required methods
    /// </summary>
    public class JuiceFactory
    {
        public JuiceProduct GetJuiceProduct(string inputType)
        {
            JuiceProduct juice = new JuiceProduct();
            string readyProduct = juice.sqeezeProduct();
 
            IMixedProduct endProduct = new MixtureProduct();
            endProduct.MixProduct(readyProduct);
            return juice;
        }
    }
 
    /// <summary>
    /// Concrete mashing factory calling required methods
    /// </summary>
    public class MashingFactory
    {
        public MashedProduct GetMashProduct(string inputType)
        {
            MashedProduct mash = new MashedProduct();
            string readyProduct = mash.mashProduct();
 
            new MixtureProduct().MixProduct(readyProduct);
            return mash;
        }
    }
 
    /// <summary>
    /// Concrete grinding factory calling required methods
    /// </summary>
    public class GrindingFactory
    {
        public FlourProduct GetGrindedProduct(string inputType)
        {
            FlourProduct flour = new FlourProduct();
            string readyProduct = flour.grindProduct();
 
            new MixtureProduct().MixProduct(readyProduct);
            return flour;
        }
    }
}

Product.cs

C#
using System;

/// <summary>
/// Observations -  
///     1. Products - One child product inheriting abstract product and three separate products
/// What's new here -
///     1. Product - One additional type of product is added
/// </summary>
namespace MultipleFactories
{
    /// <summary>
    ///  Its an essential function of blender, no matter what kind of product its going to mix
    /// </summary>
    public interface IMixedProduct
    {
        void MixProduct(string readyProduct);
    }
 
    /// <summary>
    /// Concrete product implementing essential method
    /// </summary>
    public class MixtureProduct : IMixedProduct
    {
        public  void MixProduct(string readyProduct)
        {
            Console.WriteLine(readyProduct + " is mixed.");
        }
    }
 
    /// <summary>
    /// Squeezing function for juices only
    /// </summary>
    public class JuiceProduct
    {
        public string sqeezeProduct()
        {
            return "Juice";
        }
    }
 
    /// <summary>
    /// Mashing function for boiled item only
    /// </summary>
    public class MashedProduct
    {
        public string mashProduct()
        {
            return "Mashed product";
        }
    }
 
    /// <summary>
    /// Grinding function for grain items only
    /// </summary>
    public class FlourProduct
    {
        public string grindProduct()
        {
            return "Flour";
        }
    }
}

Problem with Stage 5

I thought I am almost done with my kitchen appliances, but it does not end here, after some time I needed to grind wheat to make dough. So neither was I able to use blender or mixer for grinding wheat, nor did I want to buy (aka extra effort) one more appliance in my kitchen (aka managing code).

In Programming Terms / Point to note / Requirement Analysis

  • I wanted to get all grinding functions for all liquid, semi-liquid, solid items like fruits, vegetables, wheat, pulp, tomato, potato, etc.
  • I don’t want to compromise with specific outcome or quality.
  • I didn’t want to but many appliances, as it was neither economic, not manageable.

Stage 6 – Factory Method Pattern

(Also known as Factory method, Factory method pattern, Factory method Design pattern)

Solution

So instead of having many appliances, I decided to buy a combined JuicerMixerGrinder having separate jars.

Real World Scenario

When you want a fruit juice, you seek a juicer, so it’s kind of a small factory (Mixer – The Creator, Jar – The Concrete creator, Egg/Fruits – Raw Product, Puree/Juice – Concrete Product). So based on your item (input) you put into the mixer, it can produce puree, shake or juice. So when Mixer blends or grinds an item, it does not know, which item it’s going to crush (aka, let the subclass decides, which class is to be instantiated).

Definition (In Programming Terms)

"Factory method pattern defines an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses."

Comparing Design Pattern Terms with Real World Example

  • You – Main method
  • Mixer – The factory or creator
  • Jar – The concrete creator
  • Item – Raw Product

Solution (In Programming Terms)

There could be 2 approaches here:

Approach 1

There could be multiple concrete factories implementing specific method depend on input type and essential (common method for all product which is mixing) method defined in factory interface to instantiate final product.

Approach 2

There could be a single concrete factory implementing product specific method depend on input type and then essential (common method for all product which is mixing) method defined in factory interface to instantiate final product.

Stage 6 (Approach 1)

Class Diagram

Image 6

Implementation Code

UIClass.cs

C#
using System;
/// <summary>
/// Observations -
///     1. Object instantiation of specific factories depends on input type 
///     2. Caller of factory(UI Class in this example) knows which factory to call, 
///        but don't know which end product to prepare
/// What's new here -
///     1. This is one of the approaches for Factory method pattern, 
///        where UI class initialize specific concreate factory
/// </summary>
using System;
namespace FactoryMethod_App1
{
    /// <summary>
    /// UI code calling specific factories as per input type
    /// </summary>
    class UIClass
    {
        static void Main(string[] args)
        {
            // Code added for mixing and grinding items
            Console.WriteLine("Please enter item for Mixer : Fruit, Boiled, or Grain");           
            string itemType = Console.ReadLine();
 
            switch (itemType)
            {
                case "Fruit":
                    // Instantiating concreate factory
                    IMixerFactory juice = new JuiceFactory();
                    //Creation of product using method in factory (that is factory method)
                    IMixer mixJuice = juice.GetMixingProduct();
                    // Processing end product
                    mixJuice.MixProduct(itemType);
                    // above 2 lines of code can also be written in single line 
                    //juice.GetMixingProduct().MixProduct(itemType);
                    break;
                case "Boiled":
                   IMixerFactory boiled = new MashingFactory();
                    IMixer mash = boiled.GetMixingProduct();
                    mash.MixProduct(itemType);
                    break;
                case "Grain":
                   IMixerFactory crush = new GrindingFactory();
                    IMixer flour = crush.GetMixingProduct();
                    flour.MixProduct(itemType);
                    break;
                default :
                    throw new Exception("item type not supported");
            }
            Console.ReadKey();
        }
    }
}

Factory.cs

C#
/// <summary>
/// Observations - 
///     1. There are seperate concreate factories for all type like juice, boiled, flour
///     2. Here mixer has 3 separate jars for juicer, masher, & grinder
/// What's New -
///     1. Introduceds single factory interface to be implemented by all concreate factories
/// </summary>
namespace FactoryMethod_App1
{
    /// <summary>
    /// Observations - 
    ///     Single factory interface to be implemented by all products  
    /// </summary>
    public interface IMixerFactory
    {
        IMixer GetMixingProduct();
    } 
    /// <summary>
    ///      Concreate juice factory calling required methods
    /// </summary>
    public class JuiceFactory : IMixerFactory
    {
        public IMixer GetMixingProduct()
        {
            return new Juicer();
        }
    }
 
    /// <summary>
    /// Concrete mashing factory calling required methods
    /// </summary>
    public class MashingFactory : IMixerFactory
    {
        public IMixer GetMixingProduct()
        {
            return new Masher();
        }
    }
 
    /// <summary>
    /// Concrete grinding factory calling required methods
    /// </summary>
   public class GrindingFactory : IMixerFactory
    {
        public IMixer GetMixingProduct()
        {
            return new Grinder();
        }
    }
}

Product.cs

C#
using System;
/// <summary>
/// Observations - 
///     1. Each function is implementing interface method to process end product 
/// </summary>
namespace FactoryMethod_App1
{
    /// <summary>
    ///  Product interface
    /// </summary>
    public interface IMixer
    {
        void MixProduct(string readyProduct);
    }
 
    /// <summary>
    /// Juicer implements interface method
    /// </summary>
    public class Juicer : IMixer
    {
        public void MixProduct(string readyProduct)
        {
            Console.WriteLine(readyProduct + " juice is prepared.");
        }
    }
 
    /// <summary>
    /// Masher implements interface method
    /// </summary>
    public class Masher : IMixer
    {
        public void MixProduct(string readyProduct)
        {
            Console.WriteLine(readyProduct + " product is mashed.");
        }
    }
 
    /// <summary>
    /// Grinder implements interface method
    /// </summary>
    public class Grinder : IMixer
    {
        public void MixProduct(string readyProduct)
        {
            Console.WriteLine(readyProduct + " flour is prepared.");
        }
    }
}

Stage 6 (Approach 2)

Class Diagram

Image 7

Implementation Code

UIClass.cs

C#
using System;
/// <summary>
/// Observations -
///     1. This is another approach for Factory method pattern, 
///        where UI class initialize single concreate factory
///     2. Object instantiation of main concreate factories depends on input type using interface
/// </summary>
using System;
namespace FactoryMethod_App2
{
    /// <summary>
    /// UI code calling specific factories as per input type
    /// </summary>
    class UIClass
    {
        static void Main(string[] args)
        {
            // Code added for mixing and grinding items
            Console.WriteLine("Please enter item for Mixer : Fruit, Boiled, or Grain");           
           
             // Note - Using this method, UI code will not be changed.
            IMixerFactory liquid = new MixerFactory();
            IMixer endproduct = liquid.GetMixingProduct(Console.ReadLine());
                        
            Console.ReadKey();
        }
    }
}

Factory.cs

C#
/// <summary>
/// Observations - 
///    1. There is only one factory for all type like juice, boiled, flour
///    2. Here mixer has 3 function for juicer, masher, & grinder
/// What's New -
///    1. Single factory interface to be implemented by single concreate factory
/// </summary>
namespace FactoryMethod_App2
{
    /// <summary>
    /// Observations - 
    ///     Single factory interface to be implemented by all products
    ///     Abstract class can also be used here instead of interface 
    /// </summary>
    public interface IMixerFactory
    {
        IMixer GetMixingProduct(string inputType);
    }
    /// <summary>
    ///     Single concreate factory instantiating concreate products
    /// </summary>
    public class MixerFactory : IMixerFactory
    {
        public IMixer GetMixingProduct(string inputType)
        {
            return new Mixer(inputType);
        }
    }
}

Product.cs

C#
using System;
/// <summary>
/// Observations - 
///     1. Here Mixer implements interface method after making product ready to mix
///     2. Mixer using switch case to get specific product ready before mixing
/// </summary>
namespace FactoryMethod_App2
{
    /// <summary>
    ///  Product interface
    /// </summary>
    public interface IMixer
    {
        string GetProductReady(string readyProduct);
    }
 
    /// <summary>
    ///  Common mixing function for all item types
    /// </summary>
  public class Mixer : IMixer
    {
        public Mixer(string inputType)
        {
            string endproduct = GetProductReady(inputType);
            Console.WriteLine(inputType + " " + endproduct + " is prepared.");
        }
        // Getting product ready before mixing
        public string GetProductReady(string inputType)
        {
            string readyProduct = null;
            switch (inputType)
            {
                case "Fruit":
                    readyProduct = new Juicer().sqeezeProduct();
                    break;
                case "Boiled":
                   readyProduct = new Masher().mashProduct();
                    break;
                case "Grain":
                    readyProduct = new Grinder().grindProduct();
                    break;
                default :
                    throw new Exception("item type not supported");
            }
            return readyProduct;
        }
    }
    /// <summary>
    /// Squeezing function for fruit item 
    /// </summary>
    public class Juicer 
    {
        public string sqeezeProduct()
        {
            return "juice";
        }
    }
 
    /// <summary>
    /// Mashing function for boiled item only
    /// </summary>
   public class Masher 
    {
        public string mashProduct()
        {
            return "mashed product";
        }
    }
     /// <summary>
    /// Grinding function for solid item only
    /// </summary>
   public class Grinder
    {
        public string grindProduct()
        {
            return "flour";
        }
    }
}

FAQ

  1. Does factory pattern always need to use switch cases?

    No, it’s not essential, it always depends on the need for how to manage instantiating concrete factory

  2. Can factory method be defined in interface only as per definition it defines an interface?

    No, abstract method can also be used.

  3. As this example uses Abstract keyword for product, so is it similar to abstract factory pattern?

    No, abstract word is being used for the sake of defining a product uniquely with essential method, abstract factory pattern has different set of layers.

  4. In this example, concrete factory method using composition of methods, so is it similar to abstract factory method.

    Composition is being used so here just to instantiate single method from UI, in Abstract factory, composition of abstract method with abstract keyword is used inside definition of Abstract factory. For more details, please go through another article on abstract factory.

References

  1. https://www.dofactory.com/net/factory-method-design-pattern

    Factory

  2. https://garywoodfine.com/
  3. https://dev.to/gary_woodfine/simple-factory-pattern-in-c-and-net-core-3263
  4. https://www.oodesign.com/factory-pattern.html
  5. https://www.c-sharpcorner.com/UploadFile/akkiraju/factory-design-pattern-vs-factory-method-design-pattern/
  6. http://shop.oreilly.com/product/9780596007126.do
  7. https://www.c-sharpcorner.com/UploadFile/akkiraju/factory-design-pattern-vs-factory-method-design-pattern/
  8. https://vivekcek.wordpress.com/2013/03/17/simple-factory-vs-factory-method-vs-abstract-factory-by-example/

Points of Interest

There are many illustrations on the internet, so please go through a couple of sites to understand where to use it actually.

License

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