Reader Level:
ARTICLE

Factory Pattern vs Factory Method Pattern vs Abstract Factory Pattern

Posted by Abhishek Jain Articles | Design & Architecture August 21, 2013
This article describes the Factory Pattern, Factory Method Pattern and Abstract Factory and the differences among them.
  • 0
  • 0
  • 3735

Factory Pattern

Suppose we have two classes ClassA and ClassB.

Now I am have a Third Class or suppose a Web Page where I need to create objects of both of these class (ClassA & ClassB). So what we can do here simply is:

ClassA a = new ClassA();

ClassB b = new ClassB();

That however is not good since the client or the consumer has direct permission to create an object or you can say the client or consumer should not be responsible for creating the objects. This is because, if something changes with the initialization (creation of objects) then we need to maks changes everywhere in the consumer's files, wherever we are initializing these classes. So the best way is to give the responsibility of creation of the objects to a new class. This is known as a Factory Pattern. So whenever there is a change in the process of initialization we need to makes changes only in the Factory Pattern.

So, for this we can create a Factory Class that will have the responsibility of creating Objects. It can be either parameterized (Open-Close Principle is not followed) or can be based on reflection.

Parameterized Factory

public class SampleClass

{
}

public class ClassA : SampleClass

{
}

public
class ClassB : SampleClass
{

}

public
class Factory
{

  public SampleClass Create(int classType)

  {

        SampleClass classObject = new SampleClass();

        if (classType == 1)

        {

        classObject = new ClassA();

        }

        if (classType == 2)

        {

           classObject = new ClassB();

        }

      
//So On for every Class

      return classObject;

   }

}
 

So now for creating objects, the code will be something like this:

SampleClass a = new Factory().Create(1);

SampleClass b = new Factory().Create(2);

But this breaks the open close principle, so we can do it by reflection.

Using Reflection

public class SampleClass

{
}

public
class ClassA : SampleClass
{

}

public
class ClassB : SampleClass
{

}

public
class Factory
{

  public SampleClass Create(string className)

  {

        SampleClass instance = new SampleClass();

        var requiredClass = (from assembly in AppDomain.CurrentDomain.GetAssemblies()

        from type in assembly.GetTypes()

        where string.Equals(type.Name, className, StringComparison.OrdinalIgnoreCase)

        select type).FirstOrDefault();

        if (requiredClass != null)

        {

            instance = (SampleClass)Activator.CreateInstance(requiredClass);

        }

       return instance;

   }

}

So now for creating an object the code will be something like this:

SampleClass a = new Factory().Create("ClassA");

SampleClass b = new Factory().Create("ClassB"); 

Now we don't need to change the Factory class, but right now we are having type of classes "SampleClass", that is, both of our classes are inherited by this "SampleClass". What if a new base class is added, then we need to have multiple factories and that is fine. (But then the consumer should know which factory needs to be referred to to get the objects of that type. Also each factory can have various methods that actually create the object and return them, for example: Right now the Factory class that we created above has a method "Create" but in the future someone can create a new Factory, say "FactoryNew" to get the objects of some other type and the method that will be created and that returns the object can be named "CreateNew".) So this is where the Factory Method and Abstract Factory Pattern are relevant.

Factory Method

It's the way of imposing that every Factory should have a method "Create" that should return the desired object (sub-classes that are original factories can decide which type of object needs to be returned).

It helps the consumer to directly call a method "Create" to get the object irrespective of which factory is going to be used.

Here is the code:

public class SampleClass

{
}

public
class SampleClassA : SampleClass|
{

}

public
class SampleClassB : SampleClass
{

}

public
class ClassA : SampleClassA
{

}

public
class ClassB : SampleClassA
{

}

public
class ClassC : SampleClassB
{

}

public
class ClassD : SampleClassB
{

}

public
abstract class Factory
{

    public SampleClass GetObject(string className)

    {

        return CreateObject(className);

    }

   
//Acting as a Factory Method

    protected abstract SampleClass CreateObject(string className);

}

public
class FactoryA : Factory
{

  protected SampleClass CreateObject(string className)

  {

        SampleClass instance = new SampleClassA();

        var requiredClass = (from assembly in AppDomain.CurrentDomain.GetAssemblies()

        from type in assembly.GetTypes()

        where string.Equals(type.Name, className, StringComparison.OrdinalIgnoreCase)

        select type).FirstOrDefault();

        if (requiredClass != null)

        {

             instance = (SampleClassA)Activator.CreateInstance(requiredClass);

        }

        return instance;

   }

}

public
class FactoryB : Factory
{

  protected SampleClass CreateObject(string className)

  {

       SampleClass instance = new SampleClassB();

       var requiredClass = (from assembly in AppDomain.CurrentDomain.GetAssemblies()

       from type in assembly.GetTypes()

       where string.Equals(type.Name, className, StringComparison.OrdinalIgnoreCase)

       select type).FirstOrDefault();

       if (requiredClass != null)

       {

           instance = (SampleClassB)Activator.CreateInstance(requiredClass);

       }

      return instance;

   }

}
 

So now for creating an object the code will be something like this:


SampleClass
a = new FactoryA().GetObject("ClassA");
SampleClass
b = new FactoryA().GetObject("ClassB"); 
SampleClass
c = new FactoryB().GetObject("ClassC");
SampleClass
d = new FactoryB().GetObject("ClassD");

So what's the problem now which that stillexists, any guesses?????

As of now, everything is perfect; just one problem is remaining and that is the client or the consumer needs to create the objects of the factory (knowing that which factory will return which type of object). This problem can be eliminated by adding one more level of abstraction on Factories (in other words Factory for numerous factories). In that case the consumer doesn't need to create the object of the factory themselves, they will just provide which object they need and based on that it's the task of the parent factory to decide which factory needs to be initiated to create that kind of object). So here comes the Abstract Factory into the picture.

Abstract Factory

I don't think I need to explain what the Abstract Factory pattern is and why we need it. But anyways, the Abstract Factory is used to provide one more level of modularization by which the consumer doesn't need to worry to create an instance of the Factory. Also, the responsibility is inside the Parent Factory.

Here is the code:

public class SampleClass

{
}

public
class SampleClassA : SampleClass
{

}

public
class SampleClassB : SampleClass

public
class ClassA : SampleClassA
{

}

public
class ClassB : SampleClassA
{

}

public
class ClassC : SampleClassB
{

}

public
class ClassD : SampleClassB
{

}

public
class Factory
{

  public SampleClass GetObject(string className)

  {

          SampleClass instance = new SampleClass();

         
//Here we can have Enums or XML as Depedency Injection Container have XML to get which factory needs to be initiated for which class

        
//So we can read that value and use reflection code to initiate that Factory and call its method "CreateObject" here goes the code for that

        
//Suppose we get the name of the factory class from XML and put it ninto the string, consider we get "FactoryA" in this example

        string factoryName = "FactoryA";

        var requiredFactory = (from assembly in AppDomain.CurrentDomain.GetAssemblies()

        from type in assembly.GetTypes()

        where string.Equals(type.Name, factoryName, StringComparison.OrdinalIgnoreCase)

        select type).FirstOrDefault();

        if (requiredFactory != null)

        {

               object factoryInstance = Activator.CreateInstance(requiredFactory);

             
// Get the operation's method, invoke it, and get the return value, Factory knows method name is CreateObject

              var methodInfo = factoryInstance.GetType().GetMethod("CreateObject");

              object[] operationParameters = new object[] { className };

              instance = (SampleClass)methodInfo.Invoke(factoryInstance, System.Reflection.BindingFlags.InvokeMethod, null, operationParameters, null);

        }

        return instance;

    }

}

public
interface IFactory
{

  SampleClass CreateObject(string className);

}

public
class FactoryA : IFactory
{

  public SampleClass CreateObject(string className)

  {

          SampleClass instance = new SampleClassA();

          var requiredClass = (from assembly in AppDomain.CurrentDomain.GetAssemblies()

          from type in assembly.GetTypes()

          where string.Equals(type.Name, className, StringComparison.OrdinalIgnoreCase)

          select type).FirstOrDefault();

          if (requiredClass != null)

          {

            instance = (SampleClassA)Activator.CreateInstance(requiredClass);

          }

          return instance;

     }

}  

public class FactoryB : IFactory

{
  public SampleClass CreateObject(string className)

  {

|        SampleClass instance = new SampleClassB();

         var requiredClass = (from assembly in AppDomain.CurrentDomain.GetAssemblies()

         from type in assembly.GetTypes()

         where string.Equals(type.Name, className, StringComparison.OrdinalIgnoreCase)

         select type).FirstOrDefault();

         if (requiredClass != null)

         {

             instance = (SampleClassB)Activator.CreateInstance(requiredClass);

          }

         return instance;

    }

}


So now for creating object code will be something like this:
 

SampleClass a = new Factory().GetObject("ClassA");

SampleClass b = new Factory().GetObject("ClassB"); 

SampleClass c = new Factory().GetObject("ClassC");

SampleClass d = new Factory().GetObject("ClassD");

Note: Access modifier of Many of the classes which are created to show the working of patterns can be internal depending upon how one is going to impose the pattern and the solution structure. The Abstract Factory is normally not required in small applications.

I hope this has helped you to understand what the differences are among Factory Pattern, Factory Method Pattern and Abstract Factory.

COMMENT USING

Trending up