Translate

Sunday, July 21, 2013

Factory pattern tutorial c# (Simplified Version)

The need for factory pattern

In this example below based on the value of the paramater datasource we would need to decide which implementation of IDatasource to use. The problem with a code like this is that it does not adhere to the "closed for modification" design principle. If you add a new implementation of IDataSource called DataFromFile, then you will have to modify the code in the Main() and add a new else statement. Ideally, when you add a new implementation or switch implementation, you shouldn't have to modify code.

using System;

namespace LearnFactoryPattern
{
    class Test
    {
        static void Main()
        {
            var datasource = "SQL";

            IDataSource iData;

            if (datasource.Equals("SQL"))
            {
                iData = new DataFromSQL();
            }
            else if (datasource.Equals("XML"))
            {
                iData = new DataFromXML();
            }
            else
            {
                iData = null;
            }

            iData.GetData();//Displays Data from SQL


        }
    }

    public interface IDataSource
    {
        void GetData();

    }


    public class DataFromSQL : IDataSource
    {
        public void GetData()
        {
            Console.WriteLine("Data from SQL");
        }
    }


    public class DataFromXML : IDataSource
    {
        public void GetData()
        {
            Console.WriteLine("Data from XML");
        }
    }
  

}




To switch from DataFromSQL to DataFromXML, all I should have to do, should be to change a config setting. Factory pattern helps us achieve that.

Simple Factory Pattern

In this pattern we do not need to update the code if we want to switch implementations. All we do is make a change in the config file. These are the key things we need to do to make this happen.


  • Save the name of Implementation of IDatasource we want to use in the config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
       <appSettings>
             <add key="DataSourceImplementationName" value="DataFromSQL" />
            
       </appSettings>
</configuration>




  • Load into a Dictionary, all the implementations of IDataSource that we have in the current assembly.
       Dictionary<string, Type> dataSources; 
      
        dataSources.Add(typeName, type);//types in the assembly that implement IDataSource
  • Get the name of implementation from the config file. Pass that class name into a method. That method looks up the dictionary dataSources for a type that matches the class name (type name) we just passed in. Then it creates an instance of that for us.
    public IDataSource CreateInstance(string dataSourceName)
    {
      ......

    }

The whole code that implements this is shown below. 

using System;
using System.Configuration;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;

namespace LearnFactoryPattern
{
    class Test
    {


        static void Main()
        {
            var dataSourceName = ConfigurationManager.AppSettings["DataSourceImplementationName"].ToLower();

            var factory = new DataSourceFactory();
            var dataSource=factory.CreateInstance(dataSourceName);
            dataSource.GetData();

        }
    }

    public interface IDataSource
    {
        void GetData();

    }


    public class DataFromSQL : IDataSource
    {
        public void GetData()
        {
            Console.WriteLine("Data from SQL");
        }
    }


    public class DataFromXML : IDataSource
    {
        public void GetData()
        {
            Console.WriteLine("Data from XML");
        }
    }

    /*******************************************************/
    /**************** FACTORY BELOW ************************/
    /*******************************************************/


    public class DataSourceFactory
    {
        Dictionary<string, Type> dataSources;

        public DataSourceFactory()
        {
            LoadDataSourceTypes();
        }

        public IDataSource CreateInstance(string dataSourceName)
        {

            var dataSourceImplementationName = GetTypeToCreate(dataSourceName);
            return (IDataSource)Activator.CreateInstance(dataSourceImplementationName);

        }

        public Type GetTypeToCreate(string dataSourceName)
        {
            return dataSources[dataSourceName];
        }

        public void LoadDataSourceTypes()
        {
            dataSources = new Dictionary<string, Type>();

            var typesinCurrentAssembly = Assembly.GetExecutingAssembly().GetTypes();//Get the interfaces and classes in the current assembly
            var interfaceName = typeof(IDataSource).ToString();//"IDataSource"

            foreach (var type in typesinCurrentAssembly)
            {

                if (type.GetInterface(interfaceName) != null)//Find the types that implement IDataSource
                {
                    var typeName = type.Name.ToLower();
                    dataSources.Add(typeName, type);
                }

            }

        }
    }

}


Its called factory pattern because, you pass the name of a class to a factory and it returns an instance of that class for you.




No comments:

Post a Comment

Comments will appear once they have been approved by the moderator