Wednesday, May 25, 2016

Factory Pattern With Reflection



An important aspect of software design is the manner in which objects are created, although far more time is often spent considering the object model and object interaction. But if this simple design (of object creation) aspect is ignored, it will adversely impact the entire system. Thus, it is not only important what an object does or what it models, but also in what manner it was created. 
Factory pattern is one of the most widely used pattern for these kind of situations. In this article lets see how to use Factory pattern with Reflection.  

What is Reflection ? 

Reflection provides objects (of type Type) that describe assemblies, modules and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. If you are using attributes in your code, reflection enables you to access them. 

Example -: 

int
 i = 42;
System.Type type = i.GetType();
System.Console.WriteLine(type);

Output -: System.Int32


Factory pattern without Reflection

------------------- IFruit Interface (IFruit.cs) ---------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FactoryWithReflection
{
    interface IFruit
    {
        string Name { get; }

        void eatMe();

        void donEatMe();
    }
}

------------------- Apple Class(Apple.cs) ---------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FactoryWithReflection
{
    class Apple: IFruit
    {

        public string Name
        {
            get { return "I am an Apple"; }
        }

        public void eatMe()
        {
            Console.WriteLine("Apple -: Eat me, I'm very delicious");
        }

        public void donEatMe()
        {
            Console.WriteLine("Apple -: Don't eat me, I'm not a good fruit");
        }
    }
}


------------------- Orange Class(Orange.cs) ---------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FactoryWithReflection
{
    class Orange : IFruit
    {
        public string Name
        {
            get { return "I am an Orange"; }
        }

        public void eatMe()
        {
            Console.WriteLine("Orange -: Eat me, I'm very delicious");
        }

        public void donEatMe()
        {
            Console.WriteLine("Orange -: Don't eat me, I'm not a good fruit");
        }
    }
}

------------------- Kiwi Class(Kiwi.cs) ---------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FactoryWithReflection
{
    class Kiwi : IFruit
    {
        public string Name
        {
            get { return "I am a Kiwi"; }
        }

        public void eatMe()
        {
            Console.WriteLine("Kiwi -: Eat me, I'm very delicious");
        }

        public void donEatMe()
        {
            Console.WriteLine("Kiwi -: Don't eat me, I'm not a good fruit");
        }
    }
}


------------------- NoFruit Class(NoFruit.cs) ---------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FactoryWithReflection
{
    class NoFruit:IFruit
    {
        public string Name
        {
            get { return "I am not a Fruit"; }
        }

        public void eatMe()
        {
            Console.WriteLine("You can't eat me");
        }

        public void donEatMe()
        {
            Console.WriteLine("You can't eat me");
        }
    }
}



------------------- FruitFactory Class(FruitFactory.cs) ---------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FactoryWithReflection
{
    class FruitFactory
    {
        public static IFruit getFruit(string fruitName)
        {
            switch (fruitName)
            {
                case "Orange":
                    return new Orange();
                 
                case "Apple":
                    return new Apple();
               
                case "Kiwi":
                    return new Kiwi();
             
                default:
                    return new NoFruit();
                 
            }

        }
    }
}


------------------- Program Class(Program.cs) ---------------------


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FactoryWithReflection
{
    class Program
    {
        static void Main(string[] args)
        {
            IFruit myFruit = FruitFactory.getFruit("Orange");
            Console.WriteLine(myFruit.Name);
            myFruit.eatMe();          

            Console.ReadLine();
        }
    }
}


Factory pattern with Reflection

Change FruitFactory.cs and Program.cs Classes as below


------------------- FruitFactory Class(FruitFactory.cs) ---------------------


using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace FactoryWithReflection
{
    class FruitFactory
    {
         Dictionary<string, Type> cars;

         public FruitFactory()
        {
            TypesToReturn();
        }

        public IFruit CreateInstance(string carName)
        {
            Type t = TypeToCreate(carName);

            if (t == null)
            {
                return new NoFruit();
            }
            else
            {
                return Activator.CreateInstance(t) as IFruit;
            }
        }

        public Type TypeToCreate(string carName)
        {
            foreach (var car in cars)
            {
                if (car.Key.Contains(carName.ToUpper()))
                {
                    return cars[car.Key];
                }
            }
            return null;
        }

        public void TypesToReturn()
        {
            cars = new Dictionary<string, Type>();

            Type[] typesInCurrentAssembly = Assembly.GetExecutingAssembly().GetTypes();

            foreach (Type type in typesInCurrentAssembly)
            {
                if(type.GetInterface(typeof(IFruit).ToString()) != null)
                {
                    cars.Add(type.Name.ToUpper(), type);
                }
            }
        }
    }
}


------------------- Program Class(Program.cs) ---------------------

using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FactoryWithReflection
{
    class Program
    {
        static void Main(string[] args)
        {
            FruitFactory fruitFactory = new FruitFactory();

            IFruit myfruit = fruitFactory.CreateInstance("Orange");

            Console.WriteLine(myfruit.Name);
            myfruit.eatMe();
            //myfruit.donEatMe();

            Console.ReadLine();

        }
    }
}











0 comments:

Post a Comment