Friday, July 10, 2015

Abstract Factory Pattern

Provides a way to encapsulate a group of individual factories those have common theme (related) without specifying their concrete classes.

  • Its an important creational pattern
  • Abstract factory is an extension on factory pattern


Requirement: If you have created many factories or looking to create, client code become complex and scattered to call many factories. In that case abstract factory provides a centralized & simple way to call different individual factories using abstract factory.
Client only knows about Abstract factory & calls only Abstract factory for all individual factories.

Use: Client is able to call different related concrete factories from a single point of contact.
Client doesn't know about concrete classes & concrete factories. Client is aware only with abstract factory & abstract products (Interfaces).

Problems Solved: New concrete factories with related theme can be added without updating client.







































Sample Code:


    public abstract class AbstractFactory
    {      
        /// <summary>
        /// Get Connection Factory
        /// </summary>
        /// <param name="connectionType">
        /// 1- Sql Connection
        /// 2- Oledb Connection
        /// </param>
        /// <returns></returns>
        public abstract Connection GetConnectionObject(int connectionType)
        {
           return (new ConnectionFactory()).GetConnectionObject(connectionType);
        }

        /// <summary>
        /// Get Command Factory
        /// </summary>
        /// <param name="commandType">
        /// 1- Sql Command
        /// 2- Oledb Command
        /// </param>
        /// <returns></returns>
        public abstract Command GetCommandObject(int commandType) 
        {
           return (new CommandFactory()).GetCommandObject(commandType);
        }
     }

 
 
public class ConnectionFactory : AbstractFactory
    {
        public Override Connection GetConnectionObject(int connectionType)
        {
            Connection objConnection = null;
            if (connectionType == 1)
                objConnection = new SqlConnection();
            else if (connectionType == 2)
                objConnection = new OledbConnection();

            return objConnection;

        }

        public Override Command GetCommandObject(int CommandType)

        {
                return  null;
        }
    }

    public class CommandFactory : AbstractFactory
    {
        public Override Command GetCommandObject(int CommandType)
        {
            Command objCommand =null;

            if (CommandType == 1)
                objCommand = new SqlCommand();
            else if (CommandType == 2)
                objCommand = new OledbCommand();

            return objCommand;
        }

        public Override Connection GetConnectionObject(int connectionType)

        {
                  return  null;
        }
    }

    public interface Connection
    {
       string GetName();
    }

    public interface Command
    {
       string GetName();
    }

    public class SqlConnection : Connection
    {
        public SqlConnection()
        {
       
        }

        public string GetName()
        {          
                return "Sql Connection";         
        }
    }

    public class OledbConnection : Connection
    {
        public OledbConnection()
        {        
        }

        public string GetName()
        {
            return "Oledb Connection";
        }
    }

    public class SqlCommand : Command
    {
        public SqlCommand()
        {
        }

        public string GetName()
        {
            return "Sql Command";
        }
    } 

    public class OledbCommand : Command
    {
        public OledbCommand()
        {
           
        }

        public string GetName()
        {
            return "Oledb Command";
        }
    }


Client Code

Console.WriteLine("Enter 1 for Sql connetion, 2 for oledb connection");
int connectionType = Convert.ToInt32(Console.ReadLine().ToString());//Enter 1 or 2

Connection objConn = AbstractFactory.GetConnectionObject(connectionType);
Console.WriteLine("Returned concrete connection object is of type " + objConn.GetName());
           
Console.WriteLine("Enter value for getting command concrete object");
Console.WriteLine("Enter 1 for Sql command, 2 for oledb command");
int commandType = Convert.ToInt32(Console.ReadLine().ToString()); //Enter 1 or 2
Command objCommand = AbstractFactory.GetCommandObject(commandType);
Console.WriteLine("Returned concrete command object is of type " + objCommand.GetName());
Console.WriteLine("Restart for rewind...");

Console.ReadLine();

----------------------------------------------------
Example 2


using System;

namespace RefactoringGuru.DesignPatterns.AbstractFactory.Conceptual
{

    public interface IAbstractFactory
    {
        IAbstractProductA CreateProductA();

        IAbstractProductB CreateProductB();
    }


    class ConcreteFactory1 : IAbstractFactory
    {
        public IAbstractProductA CreateProductA()
        {
            return new ConcreteProductA1();
        }

        public IAbstractProductB CreateProductB()
        {
            return new ConcreteProductB1();
        }
    }

    // Each Concrete Factory has a corresponding product variant.
    class ConcreteFactory2 : IAbstractFactory
    {
        public IAbstractProductA CreateProductA()
        {
            return new ConcreteProductA2();
        }

        public IAbstractProductB CreateProductB()
        {
            return new ConcreteProductB2();
        }
    }


    public interface IAbstractProductA
    {
        string UsefulFunctionA();
    }

    // Concrete Products are created by corresponding Concrete Factories.
    class ConcreteProductA1 : IAbstractProductA
    {
        public string UsefulFunctionA()
        {
            return "The result of the product A1.";
        }
    }

    class ConcreteProductA2 : IAbstractProductA
    {
        public string UsefulFunctionA()
        {
            return "The result of the product A2.";
        }
    }

  
    public interface IAbstractProductB
    {

        string UsefulFunctionB();

    
        string AnotherUsefulFunctionB(IAbstractProductA collaborator);
    }

    // Concrete Products are created by corresponding Concrete Factories.
    class ConcreteProductB1 : IAbstractProductB
    {
        public string UsefulFunctionB()
        {
            return "The result of the product B1.";
        }

        public string AnotherUsefulFunctionB(IAbstractProductA collaborator)
        {
            var result = collaborator.UsefulFunctionA();

            return $"The result of the B1 collaborating with the ({result})";
        }
    }

    class ConcreteProductB2 : IAbstractProductB
    {
        public string UsefulFunctionB()
        {
            return "The result of the product B2.";
        }

    
        public string AnotherUsefulFunctionB(IAbstractProductA collaborator)
        {
            var result = collaborator.UsefulFunctionA();

            return $"The result of the B2 collaborating with the ({result})";
        }
    }


    class Client
    {
        public void Main()
        {
            // The client code can work with any concrete factory class.
            Console.WriteLine("Client: Testing client code with the first factory type...");
            ClientMethod(new ConcreteFactory1());
            Console.WriteLine();

            Console.WriteLine("Client: Testing the same client code with the second factory type...");
            ClientMethod(new ConcreteFactory2());
        }

        public void ClientMethod(IAbstractFactory factory)
        {
            var productA = factory.CreateProductA();
            var productB = factory.CreateProductB();

            Console.WriteLine(productB.UsefulFunctionB());
            Console.WriteLine(productB.AnotherUsefulFunctionB(productA));
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            new Client().Main();
        }
    }
}

No comments:

Post a Comment

CI/CD - Safe DB Changes/Migrations

Safe DB Migrations means updating your database schema without breaking the running application and without downtime . In real systems (A...