Factory Design Pattern

Introduction

This article demonstrates how and when to use a factory design pattern. This article begins with the intent of the Factory Pattern. After that, it demonstrates a logical and physical model of factory. Then step-by-step implementation of factory pattern. In the end, the article discusses how it is useful.

Consider a Scenario

Consider a scenario where you developed your application for a SQL Server database. And in the future you need to shift from SQL Server to Oracle database. Then you have to change your code if you have not designed your application using a factory method.

Intent

Define an interface for creating an object, but let subclasses decide which class to instantiate.

Logical Model

LogicalModel.jpg

Rather than creating a product directly, the client uses a factory and the factory creates the product.

Physical ModelPhysicalModel.jpg

In physical model there is Factory which is an abstract class and implementation of this abstract class is in Concrete Factory. Similarly Product is an abstract class and implementation of this abstract class in Concrete Product.

Let's try to understand using a class diagram

FactoryPattern.jpg
  • Products : Declares an abstract class to define products
  • Concrete Product : It implements the product to define a concrete object
  • Factory : An abstract class, used to create a Factory
  • Concrete Factory : It implements the factory methods declared within the factory
Step 1
  1. Open Visual Studio
  2. File >> New >> Project >> Class Library
  3. Give it the name "Product"
  4. Add one class, "DALBaseClass"
  5. Copy the following segment of code:
     
using System;using System.Data;
 
namespace Product
{
    public abstract class DALBaseClass
    {
        private string strConnectionString;
        private IDbConnection connection;
        private IDbCommand command;
        private IDbTransaction transaction;

        public string ConnectionString
        {
           
get            {
              if (strConnectionString == string.Empty || strConnectionString.Length == 0)
                    throw new ArgumentException("Invalid database connection string.");
               
              return strConnectionString;
            }
           
set            { strConnectionString = value; }
        }

        protected DALBaseClass() { }

        public abstract IDbConnection GetDataProviderConnection();
       
        public abstract IDbCommand GeDataProviderCommand();
       
        public abstract IDbDataAdapter GetDataProviderDataAdapter();
 
        #region Database Transaction

        public string OpenConnection()
        {
            string Response = string.Empty;
           
try            {
             connection = GetDataProviderConnection();
// instantiate a connection object             //connection.ConnectionString = this.ConnectionString;             //connection.Open(); // open connection             Response = ((System.Reflection.MemberInfo)(connection.GetType())).Name + "
                        Open Successfully";
            }
            
catch            {
                connection.Close();
                Response = "Unable to Open " +   
                           ((System.Reflection.MemberInfo)(connection.GetType())).Name;
            }
            return Response;
        }
 
        #endregion    }
}

Step 2
  1. Right-click on the solution file
  2. Add >> New Project >> Class Library
  3. Give it the name "Concrete Products"
  4. Create the concrete product i.e. add classes for SQL, Oracle, ODBC and OleDb and inherit the DALBaseClass i.e. Product; see:
SQL Server

using System.Data;
using System.Data.SqlClient;
using Product;
namespace ConcreteProducts
{
    public class SqlDAL : DALBaseClass
    {
        // Provide class constructors
        public SqlDAL() { }

        public SqlDAL(string connectionString)
        {
            this.ConnectionString = "Data Source=xxxx;Initial Catalog=xxxx;
                                     User ID=xxxx;Password=xxxx";
        }

        // DALBaseClass Members
        public override IDbConnection GetDataProviderConnection()
        {
            return new SqlConnection();
        }

        public override IDbCommand GeDataProviderCommand()
        {
            return new SqlCommand();
        }

        public override IDbDataAdapter GetDataProviderDataAdapter()
        {
            return new SqlDataAdapter();
        }
    }
}

Oracle

using System.Data;
using System.Data.OracleClient;
using Product;

namespace ConcreteProducts
{
    public class OracleDAL : DALBaseClass
    {
        // Provide class constructors
        public OracleDAL() { }

        public OracleDAL(string connectionString)
        {
            this.ConnectionString = "Data Source=Oracle8i;Integrated Security=yes";
        }


        // DALBaseClass Members
        public override IDbConnection GetDataProviderConnection()
        {
            return new OracleConnection();
        }
        public override IDbCommand GeDataProviderCommand()
        {
            return new OracleCommand();
        }

        public override IDbDataAdapter GetDataProviderDataAdapter()
        {
            return new OracleDataAdapter();
        }
    }
}

ODBC

using System.Data;
using System.Data.Odbc;
using Product;

namespace ConcreteProducts
{
    public class OdbcDAL : DALBaseClass
    {
        // Provide class constructors
        public OdbcDAL() { }

        public OdbcDAL(string connectionString)
        {
            this.ConnectionString = "DSN=dsnname";
        }


        // DALBaseClass Members
        public override IDbConnection GetDataProviderConnection()
        {
            return new OdbcConnection();
        }

        public override IDbCommand GeDataProviderCommand()
        {
            return new OdbcCommand();
        }

        public override IDbDataAdapter GetDataProviderDataAdapter()
        {
            return new OdbcDataAdapter();
        }
    }
}

OleDb

using System.Data;
using System.Data.OleDb;
using Product;
namespace ConcreteProducts
{
    public class OleDbDAL : DALBaseClass
    {
         // Provide class constructors
        public OleDbDAL() { }

        public OleDbDAL(string connectionString)
        {
            this.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;
                      Data Source=C:\\Development\\Mine\\DataAccessLayer\\Northwind.mdb";
        }


        // DALBaseClass Members
        public override IDbConnection GetDataProviderConnection()
        {
            return new OleDbConnection();
        }
        public override IDbCommand GeDataProviderCommand()
        {
            return new OleDbCommand();
        }

        public override IDbDataAdapter GetDataProviderDataAdapter()
        {
            return new OleDbDataAdapter();
        }
    }
}
In the above four classes you can observe one common thing which is implementation of a common abstract class.

In product there is three abstract methods and you can find the implementation of each of these three abstract methods in concrete classes.

For example in the class SqlDAL:

GetDataProviderConnection returns SqlConnection
GeDataProviderCommand returns SqlCommand
GetDataProviderDataAdapter returns SqlDataAdapter

In the same manner Oracle returns OracleConnection, OracleCommand and OracleDataAdapter. And the same for the ODBC and OleDb classes.

Now let's move on to the Factory.

Step 3
 

  1. Right-click on the solution file
  2. Add >> New Project >> Class Library
  3. Give name as Factory
  4. Create one class 'DALFactory'
using Product;
namespace Factory
{
    public enum DataProviderType
    {
        Access,
        Odbc,
        OleDb,
        Oracle,
        Sql
    }
    public abstract class DALFactory
    {
      public abstract DALBaseClass GetDataAccessLayer(DataProviderType dataProviderType);
    }
}
Here we create an abstract class DALFactory. We also create an enum to pass our db choice.

Step 4
 
  1. right-click on solution file
  2. Add >> New Project >> Class Library
  3. Give it the name "ConcreteFactory"
  4. Create one class "DbDALFactory"
using System;using ConcreteProducts;using Factory;using Product;namespace ConcreteFactory
{
    public class DbDALFactory : DALFactory
    {
       public override DALBaseClass GetDataAccessLayer(DataProviderType dataProviderType)
        {
            switch (dataProviderType)
            {
                case DataProviderType.Access:
                case DataProviderType.OleDb:
                    return new OleDbDAL();

                case DataProviderType.Odbc:
                    return new OdbcDAL();
                case DataProviderType.Oracle:
                    return new OracleDAL();
                case DataProviderType.Sql:
                    return new SqlDAL();

                default:
                    throw new ArgumentException("Invalid DAL provider type.");
            }
        }
    }
}
This class implements an abstract method of DALFactory i.e. Factory. And create an object of Concrete Product.

Now let's see how the client uses the factory.

Step 5

  1. Right-click on the solution file
  2. Add >> New Project >> Console Application
  3. Give it the name "Client"
using System;
using ConcreteFactory;
using Factory;

namespace FPClient
{
    class Program
    {
        static void Main(string[] args)
        {
            string choice = string.Empty, dbProvider = string.Empty;
            bool done = false;
            do
            {
                Console.Clear();
                Console.WriteLine("\t Select one of the Database Providers \n");
                Console.WriteLine("\t 1. Access / OleDb");
                Console.WriteLine("\t 2. Odbc");
                Console.WriteLine("\t 3. Oracle");
                Console.WriteLine("\t 4. Sql \n");
                Console.WriteLine("===============================================");
                Console.Write("\t Enter Your Selection (0 to exit) : ");
                choice = Console.ReadLine();
            
                switch (choice)
                {
                    case "0" :
                        done = true;
                        break;

                    case "1":
                        dbProvider = "Access";
                        break;

                    case "2":
                        dbProvider = "Odbc";
                        break;

                    case "3":
                        dbProvider = "Oracle";
                        break;

                    case "4":
                        dbProvider = "Sql";
                        break;
                }
                if (choice != "0")
                {
                    Console.WriteLine("===========================================");
                    DALFactory Factory = new DbDALFactory()
                    var DAL = Factory.GetDataAccessLayer((DataProviderType)Enum.Parse                                            (typeof(DataProviderType), dbProvider));
                    Console.WriteLine(DAL.OpenConnection());
                    Console.ReadKey();
                }
            } while (!done);
        }
    }
}

Here in the client code, we can see that the client creates an object of DALFactory i.e. Factory and Factory creates an object of Concrete Products. The main thing in this pattern is that the client is totally unaware of the concrete products.

Ref:http://msdn.microsoft.com/en-us/library/ee817667.aspx
http://www.codeproject.com/Articles/37547/Exploring-Factory-Pattern 
http://www.codeproject.com/Articles/716413/Factory-Method-Pattern-vs-Abstract-Factory-Pattern

Facade in C#

Façade defines a higher-level interface that makes the subsystem easier to use.


This structural code demonstrates the Facade pattern which provides a simplified and uniform interface to a large subsystem of classes.
using System;

  class MainApp
  {
    public static void Main()
    {
      Facade facade = new Facade();

      facade.MethodA();
      facade.MethodB();

      // Wait for user 
      Console.Read();
    }
  }

  // "Subsystem ClassA" 
  class SubSystemOne
  {
    public void MethodOne()
    {
      Console.WriteLine(" SubSystemOne Method");
    }
  }

  // Subsystem ClassB" 
  class SubSystemTwo
  {
    public void MethodTwo()
    {
      Console.WriteLine(" SubSystemTwo Method");
    }
  }

  // Subsystem ClassC" 
  class SubSystemThree
  {
    public void MethodThree()
    {
      Console.WriteLine(" SubSystemThree Method");
    }
  }

  // Subsystem ClassD" 
  class SubSystemFour
  {
    public void MethodFour()
    {
      Console.WriteLine(" SubSystemFour Method");
    }
  }

  // "Facade" 
  class Facade
  {
    SubSystemOne one;
    SubSystemTwo two;
    SubSystemThree three;
    SubSystemFour four;

    public Facade()
    {
      one = new SubSystemOne();
      two = new SubSystemTwo();
      three = new SubSystemThree();
      four = new SubSystemFour();
    }

    public void MethodA()
    {
      Console.WriteLine("\nMethodA() ---- ");
      one.MethodOne();
      two.MethodTwo();
      four.MethodFour();
    }

    public void MethodB()
    {
      Console.WriteLine("\nMethodB() ---- ");
      two.MethodTwo();
      three.MethodThree();
    }
  }
MethodA() ----
SubSystemOne Method
SubSystemTwo Method
SubSystemFour Method

MethodB() ----
SubSystemTwo Method
SubSystemThree Method

Dependency Injection Pattern

Dependency Injection : Instead of creating objects inside the class it allows you to inject objects
There are three types of injections are there 1) Construction Injection 2) Setter Injection 3) Interface Injection
Object Dependency Explained
When an object needs another object to operate properly, we say that the former is dependent on the latter. This behavior is transitive in nature. Consider three objects, namely, A, B, and C. If object A is coupled to object B, and B is in turn coupled to C, then object A is effectively coupled to object C—it is dependent on C. I've used the terms coupling and dependency interchangeably in this article.

Objects can be coupled in two ways: tight coupling and loose coupling. When an object is loosely coupled with another object, you can change the coupling with ease; when the coupling is tight, the objects are not independently reusable and hence are difficult to use effectively in unit test scenarios.

Here's an example of tight coupling. Consider two classes, C1 and C2, where C1 is tightly coupled with C2 and requires it to operate. In this case C1 is dependent on C2, as shown below:


   public class C2
   {
     //Some code
   }
   public class C1
   {
      C2 bObject = new C2();
      //Some code
   }
The tight coupling between the two classes shown above occurs because C1 (which is dependent on C2) creates and contains an instance of the class C2. It's "tight" because you can eliminate or change the dependency only by modifying the container class (C1). This is where dependency injection fits in.
What is Dependency Injection?
Dependency injection eliminates tight coupling between objects to make both the objects and applications that use them more flexible, reusable, and easier to test. It facilitates the creation of loosely coupled objects and their dependencies. The basic idea behind Dependency Injection is that you should isolate the implementation of an object from the construction of objects on which it depends. Dependency Injection is a form of the Inversion of Control Pattern where a factory object carries the responsibility for object creation and linking. The factory object ensures loose coupling between the objects and promotes seamless testability.

Advantages and Disadvantages of Dependency Injection
The primary advantages of dependency injection are:
  • Loose coupling
  • Centralized configuration
  • Easily testable
 =====================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private IDataAccess GetDataAccessFactory(string rqType)
        {
            string typeString = string.Empty;
            IDataAccess reqType = null;
           
            switch(rqType)
            {
                case  "Oracle":
                    typeString = "WindowsFormsApplication2.OracleDataAccess";
                    break;
                case "SQlServer":
                    typeString = "WindowsFormsApplication2.SqlDataAccess";
                    break;
            }

             Type xxx = Type.GetType(typeString);
            reqType = Activator.CreateInstance(xxx) as IDataAccess;

            return reqType;
        }



        private void Form1_Load(object sender, EventArgs e)
        {
            //Type xxx = Type.GetType("WindowsFormsApplication2.SqlDataAccess");
           // Type xxx = Type.GetType("WindowsFormsApplication2.OracleDataAccess");

            //IDataAccess reqDataAccess = Activator.CreateInstance(xxx)  as IDataAccess;

            //DataAccess da = new DataAccess(Activator.CreateInstance(xxx) as IDataAccess);

            //MessageBox.Show(da.GetData());

            DataAccess da = new DataAccess(GetDataAccessFactory("Oracle"));

            MessageBox.Show(da.GetData());


            da.RequiredObject = GetDataAccessFactory("SQlServer");
            MessageBox.Show(da.GetData());

       
        }


        private DataTable GetFulfillmentOrderReleases(int fulfillmentOrderId)
        {
            SqlConnection objCon = new SqlConnection("User ID=Automation_Service;pwd=fran-fRe;Server=MNDEV02;Database=CDMS");
            SqlDataAdapter objAdp = new SqlDataAdapter("SELECT * FROM  FulfillmentOrderReleases WHERE iPK_OrderReleaseID = " + fulfillmentOrderId.ToString(),objCon);
            DataTable dt = new DataTable();
            objAdp.Fill(dt);

            return dt;
        }

        private List GetListForTable(DataTable dt) where T : new()
        {
            List reqList = new List();

            Type reqType = typeof(T);

            foreach (DataRow dr in dt.Rows)
            {

                //T reqObj = Activator.CreateInstance();
                T reqObj = new T();


                PropertyInfo[] propInfo = reqType.GetProperties();

                foreach (PropertyInfo prop in propInfo)
                {
                    prop.SetValue(reqObj, dr[prop.Name]);
                }
                reqList.Add(reqObj);
            }

            return reqList;
        }
    }

    public interface IDataAccess
    {
        string GetData();
    }


    public class DataAccess
    {
        private IDataAccess reqObject;
        public  IDataAccess RequiredObject
        {
            get
            {
                return reqObject;
            }
            set
            {
                reqObject = value;
            }

        }


        public DataAccess(IDataAccess pReqObject)
        {
            reqObject = pReqObject;
        }

        public string GetData()
        {
            return reqObject.GetData();
        }

    }

    public class SqlDataAccess : IDataAccess
    {
        public string GetData()
        {
            return "This data is comming from SQL";
        }
    }

    public class OracleDataAccess : IDataAccess
    {
        public string GetData()
        {
            return "This data is comming from Oracle";
        }
    }

    public class FulfillmentOrderReleases
    {
        public int iPK_OrderReleaseID  { get; set;}
        public int iFK_FulfillmentOrderID{get;set;}
        public int iFK_ParentOrderReleaseID { get; set; }
        public DateTime dt_DateEntered { get; set; }
        public int iFK_EnteredByID { get; set; }
        public int iFK_LocationID { get; set; }
        public DateTime dt_RequiredShipDate { get; set; }
        public int iFK_PreferredServiceLevelID { get; set; }
        public int i_Status { get; set; }
        public int b_Complete { get; set; }
        public DateTime dt_DateCompleted { get; set; }
        public string vch_PurchaseOrder { get; set; }
        public string vch_ERP_ID { get; set; }

    }


}