Factory Method with C#

Factory method is a creational design pattern which solves the problem of creating product objects without specifying their concrete classes.

Factory Method defines a method, which should be used for creating objects instead of direct constructor call (new operator). Subclasses can override this method to change the class of objects that will be created.

Structure

factory method with c sharp by Younes Rabdi

Factory Method C# Example Code

In this example, we have a game application with different worlds, every world is a vast map with it’s own creatures and logic. We will have hundreds of different worlds in the future. The Difficulty :

In our main program, we want to load a world. We do not know how many worlds we will have in the future and we do not want to change code of the main logic just because we added a different world to the game. Solution with Factory Method : The Factory Method pattern suggests that you replace direct object construction calls (using the new operator) with calls to a special factory method. Don’t worry: the objects are still created via the new operator, but it’s being called from within the factory method. Objects returned by a factory method are often referred to as products.

The C# Code

using System;
using System.Collections.Generic;

namespace FactoryMethodDP
{
    /// World interface
    public interface IWorld
    {
        void SpawnWorld();
        void SpawnCreatures();
    }

    /// Concret World 1
    public class Africa : IWorld
    {
        public void SpawnWorld()
        {
            Console.WriteLine("Run complex Africa logic");
        }

        public void SpawnCreatures()
        {
            Console.WriteLine("Spawn lions, girafs, elephants.");
        }
    }

    /// Concret World 2
    public class America : IWorld
    {
        public void SpawnWorld()
        {
            Console.WriteLine("Run complex America logic");
        }

        public void SpawnCreatures()
        {
            Console.WriteLine("Spawn Bears, Ducks, Wolves.");
        }
    }

    /// Concret Base creator
    public abstract class Creator
    {
        /// Subclasses will override this method in order to create specific world
        public abstract IWorld WorldFactoryMethod();

        /// static method to get the related World Factory 
        public static Creator GetFactory(string p_WorldName)
        {
            Creator c;

            switch (p_WorldName)
            {
                /*case "moon":
                    c = new MoonWorld(); break;
                  case "andromeda":
                    c = new AndromedaWorld(); break;
                case "aurora":
                    c = new AuroraWorld(); break;*/
                case "america":
                    c = new AmericaFactory(); break;
                default:
                    c = new AfricaFactory(); break;
            }

            return c;
        }


        /// This can be a useful way to get all the available products so the main 
        ///  application won't need to know in advance how many worlds are there.
        public static List GetNamesOfAvailableWorlds()
        {
            return new List() { "america", "africa" };
        }
    }

    /// Concret creator 1
    public class AfricaFactory : Creator
    {
        public override IWorld WorldFactoryMethod()
        {
            return new Africa();
        }
    }

    /// Concret creator 2
    public class AmericaFactory : Creator
    {
        public override IWorld WorldFactoryMethod()
        {
            return new America();
        }
    }

    /// All of the main code should work with factories and products through
    /// abstract interfaces. This way it does not care which factory or product it works with.
    class Program
    {
        static void Main(string[] args)
        {
            // Ask user which world to load. (this is only for demo. 
            Console.Write("console app Started. \nwhich map to load : ");
            foreach (string name in Creator.GetNamesOfAvailableWorlds())
                Console.Write(name + ", ");
            Console.WriteLine(" ?");

            // User's input to define which world to spawn
            //  PS: A better way to load a map can be used instead of asking user to type the name :)
            string worldName = Console.ReadLine();

            // Get the Concret World Creator usgin the static function provided in Base Creator.
            Creator worldCreator = Creator.GetFactory(worldName.Trim().ToLower());

            // Getting the world to work with without knowing it's concrete class
            IWorld world = worldCreator.WorldFactoryMethod();

            // I don't know what continent concrete class is, but I can work with it.
            world.SpawnWorld();
            world.SpawnCreatures();


            Console.ReadLine();
        }
    }
}