Jump to content
Aerosol

All About Abstract Factory Pattern

Recommended Posts

Posted

Introduction

This is the first pattern falls under the creational design pattern defined by "Gang of Four".

This pattern is about creating factory of factories for object creation.

What problem it solves

It solves the problem pertaining to object creation, and this process can be re-used several times without having change in client code.

About the Article

This article mainly focuses on how and where to use the Abstract Factory patterns by class diagram, working of each class with conceptual explanation and real world example.

Since it provides step-by-step information for each and every part of this pattern in the context of its significance, utility, way to use, and real world scenario, this should be easily understandable for beginners too.

Who should read this article?

  1. If you are novice for abstract factory design patterns.
  2. If you have gone through the abstract factory example many times but still confused, since you not able to map the code with its class diagram.
  3. If you want to know that what each class in the pattern does and how.

Definition

"Gang of Four" defines this pattern as follows:

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

Narrated - Provide an Interface / Abstract Class (of Product/Factory) for creating families of related or dependent objects without specifying their concrete classes (ConcreateProduct/ConcreteFactory).

image001.png

How the classes inside pattern works (What the each class does)

Main Method –

  • Instantiate the "ConcreteFactory" to get the object/instance of "AbstractFactory" return.
  • Instantiate the "Client" for delegating the responsibility of instantiating the instance of ConcreteProduct.
  • Uses instance of Client class to invoke methods defined inside Client class to create ConcreteProduct.

AbstractProduct (Abstract Class/Interface)-

It defines the method(s) that how the actual product will be created.

ConcreteProduct –( a default class)

Here the functionality of implementing actual product is defined.

It defines the actual product(s) to be created/returned from ConcreteFactory.

Note –

Each product defined here should be unique in some sense (i.e. by Type, Location, Factory etc.)

Adding a ConcreteProduct here implies that it is implementing the method(s) defined in inherited AbstractProduct and this ConcreteProduct will be returned by method implemented by a ConcreteFactory.

AbstractFactory-( Abstract Class/Interface)

Here AbstractFactory defines the AbstractProduct to be produced (could be in composition; decided by Client that how to use them), but it does not know, what concrete product actually going to be produced.

Note –

There could be 1 to n number of AbstractProduct(s) defined, the only care need to be taken is, whatever is being produced here, will be through composition, and each factory will have to produce all the AbstractProduct(s) whatever defined here.

E. ConcreteFactory-

Object/instance creation of Concrete product takes place here by implementing all the AbstractProduct defined inside AbstractFactory and instantiating the actual ConcreteProduct.

Note –

Since AbstractFactory pattern also called Factory of factories, they can be 2 or more ConcreteFactories to be used by single Client

Client –

  • Client must know about the Abstract Classes for Product and Factory, since it needs to use all the Abstract Products defined in Abstract Factory.
  • It can also be used as an interaction environment for Abstract Products.
  • The intent of AbstractFactory Pattern lies here that Client even doesnot know, which ConcreateFactory its going to use to invoke the methods defined inside AbstractFactory for creating actual product.

Note –

At a time it can instantiate a single ConcreteFactory to create all its object/instance(s). So it need to be called twice from main method in case of creating object/instance from 2 different factories.

image002.png

Before using the Code

  • The example provided here is simple console type application.
  • Each class and method having code comments, which explains how the code works.
  • Its a real world scenario of generating Payslip in PDF/Excel format for different offices of same company in various countries.
  • The example shown here uses Class/MethodName_Categoty/Type (i.e. Payslip_AbstractFactory), so that each and every class or method name can be self explanatory.
  • While using object/instance, its initial is "o" (i.e. oAbstractFactory).

The real world example (in C#)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AbstractFactory
{
class Program
{
static void Main(string[] args)
{
// Instantiating & Initializing the ConcreteFactory class to get the instance of its parent class AbstractFactory return
Document_AbstractFactory oAbstractFactory_AsiaPayslip = new AsiaPayslip_ConcreteFactory();
Document_AbstractFactory oAbstractFactory_EuropePayslip = new EuropePayslip_ConcreteFactory();

// Instantiating & Initializing the Client class
// in order to delegate the responsibility of invoking the method(s) defined inside the AbstractFactory
PrintClient oPrintClientAsia = new PrintClient(oAbstractFactory_AsiaPayslip);
PrintClient oPrintClientEurope = new PrintClient(oAbstractFactory_EuropePayslip);

// Invoke the method to get the actual product using object of Client
oPrintClientAsia.Print();
oPrintClientEurope.Print();

Console.ReadKey();
}
}

#region AbstractProduct
/// <summary>
/// Abstract Class/Interface : it defines the method that how the actual product will be created
/// </summary>
abstract class PDFDocument_AbstractProduct
{
public abstract void PrintPDF();
}
abstract class ExcelDocument_AbstractProduct
{
public abstract void PrintExcel();
}

#endregion

#region ConcreteProduct
/// <summary>
/// The 'Product A1 to be returned from Factory A' class
/// Here the functionality of implementating actual product is defined.
/// </summary>
class PayslipIndia_ConcreteProduct : PDFDocument_AbstractProduct
{
public override void PrintPDF()
{
Console.WriteLine(this.GetType().Name + ": Here are the details for 'Salary-India' in PDF");
}
}
/// <summary>
/// The 'Product A2 to be returned from Factory A' class
/// </summary>
class PayslipJapan_ConcreteProduct : ExcelDocument_AbstractProduct
{
public override void PrintExcel()
{
Console.WriteLine(this.GetType().Name + ": Here are the details for 'Salary-Japan' in Excel");
}
}
/// <summary>
/// The 'Product B1 to be returned from Factory B' class
/// </summary>
class PayslipUK_ConcreteProduct : PDFDocument_AbstractProduct
{
public override void PrintPDF()
{
Console.WriteLine(this.GetType().Name + ": Here are the details for 'Salary-UK' in PDF");
}
}
/// <summary>
/// The 'Product B2 to be returned from Factory B' class
/// </summary>
class PayslipFrance_ConcreteProduct : ExcelDocument_AbstractProduct
{
public override void PrintExcel()
{
Console.WriteLine(this.GetType().Name + ": Here are the details for 'Salary-France' in Excel");
}
}

#endregion

#region AbstractFactory
/// <summary>
/// Here factory defines the AbstractProduct to be produced (could be in composition; decided by Client)
/// but it does not know, what concrete product actually going to be produced.
/// </summary>
abstract class Document_AbstractFactory
{
public abstract PDFDocument_AbstractProduct GetPDFObject_AbstractProduct();
public abstract ExcelDocument_AbstractProduct GetExcelObject_AbstractProduct();
}

#endregion

#region ConcreteFactory
/// <summary>
/// The 'ConcreteFactory A' class : The 'ConcreteCreator'(in FactoryMetod)/'ConcreteFactory'(in AbstractFactory pattern)
/// Object creation preocess of Concrete products takes place here
/// </summary>
class AsiaPayslip_ConcreteFactory : Document_AbstractFactory
{
public override PDFDocument_AbstractProduct GetPDFObject_AbstractProduct()
{
return new PayslipIndia_ConcreteProduct();
}

public override ExcelDocument_AbstractProduct GetExcelObject_AbstractProduct()
{
return new PayslipJapan_ConcreteProduct();
}
}
/// <summary>
/// The 'ConcreteFactory B' class
/// </summary>
class EuropePayslip_ConcreteFactory : Document_AbstractFactory
{
public override PDFDocument_AbstractProduct GetPDFObject_AbstractProduct()
{
return new PayslipUK_ConcreteProduct();
}

public override ExcelDocument_AbstractProduct GetExcelObject_AbstractProduct()
{
return new PayslipFrance_ConcreteProduct();
}
}
#endregion

#region Client
/// <summary>
/// This decides how the final product will be prepared.
/// </summary>
class PrintClient
{
PDFDocument_AbstractProduct oPDF_AbstractProduct;
ExcelDocument_AbstractProduct oExcel_AbstractProduct;

// Client Constructor
public PrintClient(Document_AbstractFactory oAbstractFactory)
{
oPDF_AbstractProduct = oAbstractFactory.GetPDFObject_AbstractProduct();
oExcel_AbstractProduct = oAbstractFactory.GetExcelObject_AbstractProduct();
}
public void Print()
{
oPDF_AbstractProduct.PrintPDF();
oExcel_AbstractProduct.PrintExcel();
}
}
#endregion
}

Output

image003.png

Points of Interest

Here are some pattern observations which conclude that when to use it:

  • The keyword "new" is being used in "Concrete Factory" & main method only. So the instance creation is taking place at two places only, or we can say just one, since main method is not the conceptual part of this pattern. Thus saves a lots of memory consumptions.
  • Since adding n number of Factories will not require any change in client code, where actual Object/instance is being invoked (not instantiated) using instance of Abstract Factory, so this can be useful when number of ConcreteFatory may be increased in future
  • This can also be used in cases where the process of making actual product is very well defined and fixed. Since making changes in Abstract Factory is not advisable.
  • When you need to keep the details of object/instances instantiation(at Client) separate,
  • or The creation of object/instances(at client) should be independent from the utilizing system(main method)
  • or Concrete classes should be decoupled from clients.
  • Since more than one AbstractProduct can be defined under single AbstractFactory,
  • it can be used in such cases where a task requires to use more than 1 process as composition
  • Since instantiating a single or multiple concreateFactory can be managed in main method.
  • it can also be used in scenarios where System requires to work with multiple families of products or instactiation of factory has to be decided at run-time under main method.

FAQ

Is there any restriction of using abstract class?

No, Interface can also be used in place of Abstract class, as required.

Is there any limitation on using concrete class (Product/Factory)?

No, but there ideally they should be 2 or more, otherwise Factory pattern can be used if there is one concrete product and one concrete factory (which is called ConcreteCreator in Factory method)

Is there compulsory use of Client in Abstract Factory?

Yes, Client plays a very important role here,

First it does not know about the concrete classes, so adding n number of concrete classes does not require any change here.

Second it invokes the AbstractFactory to create product.

Third it can also serves as interaction environment for AbstractProduct if required.

Source

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...