Abstract Factory Design Pattern in .NET — Real-Time Finance Example
The Abstract Factory pattern is used to create families of related or dependent objects without specifying their concrete classes. It’s especially useful when objects must be created together and must be compatible with one another.
Purpose
To encapsulate
the creation of related objects and ensure the client uses compatible types
from the same family. This helps maintain consistency and allows easy
replacement of entire families.
Key Characteristics
- Defines a factory
interface for a group of related products
- Each concrete
factory creates a specific variant of each product
- Ensures that
the created products work together properly
Pros
- Promotes consistency
among related objects
- Supports the
Open/Closed Principle
- Keeps client
code independent of concrete implementations
Cons
- Can result
in complex class hierarchies
- Extending
families can be
harder without modifying interfaces
Use Cases
- UI themes:
Create consistent buttons, dropdowns, inputs for dark/light themes
- Payment
Gateways: Different services (auth, refund, settlement) for Razorpay,
Stripe, etc.
- Report
Generators: Create consistent headers/bodies for PDF, Excel, CSV formats
Real-Time Finance Example: Financial Report
Generation
A banking system
needs to generate reports in multiple formats (PDF, Excel). Each format
must have a header and body that are visually and structurally
compatible. The Abstract Factory pattern ensures that the correct parts are
created as a set.
1. Define Abstract Product Interfaces
public interface IReportHeader
{
void
PrintHeader();
}
public interface IReportBody
{
void
PrintBody();
}
2. Implement Concrete Products
// PDF products
public class PDFHeader : IReportHeader
{
public void PrintHeader()
{
Console.WriteLine("PDF Header: Financial Report");
}
}
public class PDFBody : IReportBody
{
public void PrintBody()
{
Console.WriteLine("PDF Body: Revenue, Expenses, Profit...");
}
}
// Excel products
public class ExcelHeader : IReportHeader
{
public void PrintHeader()
{
Console.WriteLine("Excel Header: Financial Report");
}
}
public class ExcelBody : IReportBody
{
public void PrintBody()
{
Console.WriteLine("Excel Body: Revenue, Expenses, Profit...");
}
}
3. Define the Abstract Factory
public interface IReportFactory
{
IReportHeader CreateHeader();
IReportBody CreateBody();
}
4. Implement Concrete Factories
public class PDFReportFactory : IReportFactory
{
public IReportHeader CreateHeader() => new PDFHeader();
public IReportBody CreateBody() => new PDFBody();
}
public class ExcelReportFactory :
IReportFactory
{
public IReportHeader CreateHeader() => new ExcelHeader();
public IReportBody CreateBody() => new ExcelBody();
}
5. Client Code (Uses Only Abstractions)
public class ReportGenerator
{
private readonly IReportHeader _header;
private readonly IReportBody _body;
public ReportGenerator(IReportFactory factory)
{
_header = factory.CreateHeader();
_body = factory.CreateBody();
}
public
void GenerateReport()
{
_header.PrintHeader();
_body.PrintBody();
}
}
6. Usage Example
class Program
{
static void Main()
{
Console.WriteLine("Generating PDF Report:");
var pdfReport = new ReportGenerator(new
PDFReportFactory());
pdfReport.GenerateReport();
Console.WriteLine();
Console.WriteLine("Generating Excel Report:");
var excelReport = new ReportGenerator(new ExcelReportFactory());
excelReport.GenerateReport();
}
}
Output
Generating PDF Report:
PDF Header: Financial Report
PDF Body: Revenue, Expenses, Profit...
Generating Excel Report:
Excel Header: Financial Report
Excel Body: Revenue, Expenses, Profit...
Benefits of This Design
- Ensures
components created together are compatible and consistent
- Allows easy
addition of new families (e.g., CSVReportFactory)
- Keeps the
client focused on what to generate, not how to generate it
Comments
Post a Comment