Monday, January 28, 2013

Factory Design Pattern

Define an interface for creating an object, but let sub-classes decide which class to instantiate. Factory Method lets a class defer instantiation to sub-classes.
1. Its a creational pattern.
2. As its name say its to construct some thing.



Problems those solved by this pattern
1. So much of new keywords.
2. Client aware always about all concrete classes.
3. If we need to add / remove a concrete class then client should know about it, code updation required in client code.

Switch(invoiceType)
{
Case : 1
{
objInvoice = new invoiceWithHeader();
}
Case : 2
{
objInvoice = new invoiceWithFooter();
}
:
:
}

Benefits:
1. Reduces no. of new keywords.
2. Client just know about Factory and interface(that is implemented by all concrete classes) only.
3. No changes required at client whenever need to add a new concrete class or need to remove a concrete class.

Conclusion:

When you design an application just think if you really need it a factory to create objects. Maybe using it will bring unnecessary complexity in your application. If you have many objects of the same base type and you manipulate them mostly casted to abstract types, then you need a factory.


Code:
namespace FactoryPatternConsole

{
    //Invoice interface
    public interface IInvoice
    {
        void PrintInvoice();
    }
}

namespace FactoryPatternConsole
{   //Invoice factory
    class InvoiceFactory
    {
        public IInvoice GetInvoice(int invoiceType)
        {
            switch (invoiceType)
            {
                case 1:
                    return new clsInvoiceWithHeader();
                case 2 :
                    return new clsInvoiceWithFooter();
                default :
                    return null;
            }
        }
    }
}

namespace FactoryPatternConsole
{
    //Client
    class Program
    {
        static void Main(string[] args)
        {
            InvoiceFactory objFactory = new InvoiceFactory();
            //Here client just need to pass invoice type code to get required invoice
            IInvoice objInvoice = objFactory.GetInvoice(2);
            objInvoice.PrintInvoice();
            Console.ReadLine();
        }
    }
}

namespace FactoryPatternConsole
{
    //Concrete class invoice with header
    class clsInvoiceWithHeader : IInvoice
    {
        public void PrintInvoice()
        {
            Console.WriteLine("This is an invoice with header.");
        }
    }
}


namespace FactoryPatternConsole
{
    //Concrete class invoice with footer
    class clsInvoiceWithFooter : IInvoice
    {
        public void PrintInvoice()
        {
            Console.WriteLine("This is an invoice with footer.");
        }
    }
}

Benefits

  • Decouples object creation logic
  • Centralizes creation (easy to change later)
  • Supports adding new types easily


🧠 Real Uses in .NET Core

  1. Dependency Injection Container (built-in factory)

    • When you call builder.Services.AddTransient<IMyService, MyService>(),
      the DI container acts as a factory, creating MyService instances as needed.

  2. LoggerFactory

    ILoggerFactory loggerFactory = LoggerFactory.Create(builder => {     builder.AddConsole();

    });

    var logger = loggerFactory.CreateLogger<Program>();

  3. DbContextFactory (EF Core 5+)

    var factory = new PooledDbContextFactory<AppDbContext>();

    using var context = factory.CreateDbContext();

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...