Factory Method Pattern | Creational Design Pattern

Factory Method Pattern 

The Factory Method Pattern is a creational design pattern that provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created. It promotes the idea of "deferring the instantiation to subclasses." This pattern is particularly useful when a class cannot anticipate the class of objects it needs to create.


Key components and concepts involved in the Factory Method Pattern:


1. Product:

   - Declares the interface for the objects that the factory method will create.


2. Concrete Product:

   - Implements the `Product` interface.


3. Creator:

   - Declares the factory method, which returns an object of type `Product`. It may also contain other methods that operate on `Product` objects.


4. Concrete Creator:

   - Overrides the factory method to return an instance of a specific `Concrete Product`.


Example in C#:


// Product

interface IProduct

{

    void Display();

}


// Concrete Product A

class ConcreteProductA : IProduct

{

    public void Display()

    {

        Console.WriteLine("Concrete Product A");

    }

}


// Concrete Product B

class ConcreteProductB : IProduct

{

    public void Display()

    {

        Console.WriteLine("Concrete Product B");

    }

}


// Creator

interface ICreator

{

    IProduct FactoryMethod();

}


// Concrete Creator A

class ConcreteCreatorA : ICreator

{

    public IProduct FactoryMethod()

    {

        return new ConcreteProductA();

    }

}


// Concrete Creator B

class ConcreteCreatorB : ICreator

{

    public IProduct FactoryMethod()

    {

        return new ConcreteProductB();

    }

}


// Client

class Client

{

    public void DisplayProduct(ICreator creator)

    {

        IProduct product = creator.FactoryMethod();

        product.Display();

    }

}


// Usage

class Program

{

    static void Main()

    {

        Client client = new Client();


        // Client uses Creator A

        ICreator creatorA = new ConcreteCreatorA();

        client.DisplayProduct(creatorA);


        // Client uses Creator B

        ICreator creatorB = new ConcreteCreatorB();

        client.DisplayProduct(creatorB);

    }

}



In this example:


- The `IProduct` interface declares the `Display` method that concrete products will implement.

- Concrete products (`ConcreteProductA` and `ConcreteProductB`) implement the `IProduct` interface.

- The `ICreator` interface declares the `FactoryMethod`, which is responsible for creating an instance of `IProduct`.

- Concrete creators (`ConcreteCreatorA` and `ConcreteCreatorB`) implement the `ICreator` interface and provide their own implementation of the `FactoryMethod`.

- The `Client` class uses the factory method to create and display products without knowing the specific concrete product classes.


The key benefit of the Factory Method Pattern is that it allows the client to work with abstract product interfaces and creators, promoting flexibility and extensibility. Subclasses can override the factory method to produce different product variations, and clients can use the same interface to work with various product implementations.


A real-world example of the Factory Method Pattern can be found in the development of document processing applications where different document types need to be created. Let's consider a scenario of a document editor that supports various document formats such as PDF and Word.


Real-world Example: Document Editor


1. Product: `Document`

   - Declares the interface for documents.


2. Concrete Products: `PDFDocument`, `WordDocument`

   - Implement the `Document` interface for specific document types.


3. Creator: `DocumentCreator`

   - Declares the factory method for creating documents.


4. Concrete Creators: `PDFDocumentCreator`, `WordDocumentCreator`

   - Implement the `DocumentCreator` interface and provide their own implementation of the factory method.


Example in C#:


// Product

interface Document

{

    void Open();

    void Save();

}


// Concrete Product: PDFDocument

class PDFDocument : Document

{

    public void Open()

    {

        Console.WriteLine("Opening PDF document");

    }


    public void Save()

    {

        Console.WriteLine("Saving PDF document");

    }

}


// Concrete Product: WordDocument

class WordDocument : Document

{

    public void Open()

    {

        Console.WriteLine("Opening Word document");

    }


    public void Save()

    {

        Console.WriteLine("Saving Word document");

    }

}


// Creator

interface DocumentCreator

{

    Document CreateDocument();

}


// Concrete Creator: PDFDocumentCreator

class PDFDocumentCreator : DocumentCreator

{

    public Document CreateDocument()

    {

        return new PDFDocument();

    }

}


// Concrete Creator: WordDocumentCreator

class WordDocumentCreator : DocumentCreator

{

    public Document CreateDocument()

    {

        return new WordDocument();

    }

}


// Client

class DocumentEditor

{

    public void EditDocument(DocumentCreator documentCreator)

    {

        Document document = documentCreator.CreateDocument();

        document.Open();

        document.Save();

    }

}


// Usage

class Program

{

    static void Main()

    {

        DocumentEditor documentEditor = new DocumentEditor();


        // Editing a PDF document

        DocumentCreator pdfDocumentCreator = new PDFDocumentCreator();

        documentEditor.EditDocument(pdfDocumentCreator);


        // Editing a Word document

        DocumentCreator wordDocumentCreator = new WordDocumentCreator();

        documentEditor.EditDocument(wordDocumentCreator);

    }

}



In this example, the `DocumentCreator` interface declares the factory method `CreateDocument`, and concrete creators (`PDFDocumentCreator` and `WordDocumentCreator`) provide their own implementations. The client (`DocumentEditor`) uses the factory method to create and edit documents without knowing the specific document classes.


This pattern allows for the extensibility of the document editor to support additional document formats in the future. Each document format is encapsulated within its concrete creator, and the client can easily switch between document types without modifying the client code.




Comments