Month End Sale: Get Extra 10% OFF on Job-oriented Training! Offer Ending in
D
H
M
S
Get Now
Factory Design Pattern in C#: A Guide to Flexible Object Creation

Factory Design Pattern in C#: A Guide to Flexible Object Creation

26 Jul 2024
Intermediate
121K Views
16 min read
Learn via Video Course & by Doing Hands-on Labs

⭐ .NET Design Patterns Course: Design Patterns in C# Online Training

Factory Design Pattern in C#

The Factory Design Pattern is a basic idea in C#'s object-oriented programming. It enables you to generate objects without defining the specific type of object that will be created. This pattern encapsulates object generation, making it easier and more manageable. Using a factory method or factory class allows you to abstract away the instantiation process, resulting in a more modular and scalable solution.

In this C# tutorial, we'll look at the Factory Design Pattern, explain what it is and when to use it, and provide examples to demonstrate its application. Let us begin by examining the following question: "What is the Factory Design Pattern?"

What is the Factory Method Pattern?

  • The Factory Method Pattern is a design pattern that provides an interface for creating objects while allowing subclasses to determine the type of objects to be made. Bypassing the instantiation process to subclasses encourages loose coupling.
  • Consider a logistics company that uses a variety of transportation methods, such as trucks, ships, and planes. 
  • The company may utilize a factory method to generate the proper transportation object depending on the individual requirements, allowing for simple extension or modification of transportation kinds without affecting the core logistics code.

Understanding the Problem of not using the Factory Design Pattern

When you do not use the Factory Design Pattern, you may encounter various issues:
  • Tight coupling: occurs when your code is tightly bound to specific classes, making it impossible to change or extend the types of objects created without modifying the current code. This can result in decreased flexibility and more maintenance effort.
  • Code Duplication: Without a factory, object creation code is frequently duplicated across the program. This redundancy can cause inconsistencies and problems in the code, making it more challenging to manage.
  • Difficulty in Testing: Testing components based on specific implementations might be tricky. Using a factory allows you to simply change out implementations for testing, making your code more testable and reusable.
  • Scalability Issues: As your application expands, managing object creation directly in client code can become inefficient. The Factory Design Pattern centralizes object generation, making it more scalable and maintainable.
The Factory Design Pattern addresses these concerns, resulting in more manageable, versatile, and scalable code.

Example without using the Factory Pattern in C#

Example

using System;

public abstract class Document
{
    public abstract void Open();
}

public class WordDocument : Document
{
    public override void Open()
    {
        Console.WriteLine("Opening a Word document.");
    }
}

public class PDFDocument : Document
{
    public override void Open()
    {
        Console.WriteLine("Opening a PDF document.");
    }
}

public class DocumentManager
{
    public void OpenDocument(string type)
    {
        Document doc;

        if (type == "Word")
        {
            doc = new WordDocument();
        }
        else if (type == "PDF")
        {
            doc = new PDFDocument();
        }
        else
        {
            throw new ArgumentException("Invalid document type");
        }

        doc.Open();
    }
}

class Program
{
    static void Main()
    {
        DocumentManager manager = new DocumentManager();

        manager.OpenDocument("Word"); // Output: Opening a Word document.
        manager.OpenDocument("PDF");  // Output: Opening a PDF document.
    }
}

In this code, the DocumentManager class uses conditional logic to create WordDocument or PDFDocument objects based on the document type specified. This technique ties DocumentManager to specific document types and necessitates modification of the OpenDocument function whenever new document types are added, making it less flexible and more challenging to maintain.

After Implementing the Factory Design Pattern in C#

Example

using System;

// Abstract Product
public abstract class Document
{
    public abstract void Open();
}

// Concrete Product 1
public class WordDocument : Document
{
    public override void Open()
    {
        Console.WriteLine("Opening a Word document.");
    }
}

// Concrete Product 2
public class PDFDocument : Document
{
    public override void Open()
    {
        Console.WriteLine("Opening a PDF document.");
    }
}

// Factory
public static class DocumentFactory
{
    public static Document CreateDocument(string type)
    {
        switch (type)
        {
            case "Word":
                return new WordDocument();
            case "PDF":
                return new PDFDocument();
            default:
                throw new ArgumentException("Invalid document type");
        }
    }
}

// Client Code
class Program
{
    static void Main()
    {
        try
        {
            // Use the factory to create a WordDocument
            Document wordDoc = DocumentFactory.CreateDocument("Word");
            wordDoc.Open(); // Output: Opening a Word document.

            // Use the factory to create a PDFDocument
            Document pdfDoc = DocumentFactory.CreateDocument("PDF");
            pdfDoc.Open(); // Output: Opening a PDF document.

            // Attempting to create an invalid document type
            Document invalidDoc = DocumentFactory.CreateDocument("Excel");
            invalidDoc.Open(); // This line will throw an exception
        }
        catch (ArgumentException ex)
        {
            Console.WriteLine(ex.Message); // Output: Invalid document type
        }
    }
}

In this example, the DocumentFactory class centralizes the generation of Document objects, allowing the client code in the Main method to request documents without knowing which classes are involved. This technique simplifies object generation, increases flexibility by eliminating reliance on specific implementations, and makes document types easier to manage and extend.

Factory Method Pattern - UML Diagram & Implementation

The UML class diagram for the implementation of the factory method design pattern is given below:

Factory Method Pattern

The classes, interfaces, and objects in the above UML class diagram are as follows:

Product
  • Role: Interface
  • Purpose: Specify a standard interface for factory-created items. It assures that all concrete products follow the same set of processes.
ConcreteProduct
  • Role: Class
  • Purpose: This class implements the Product interface and its specialized implementation. It defines the product's concrete behavior and attributes.
Creator
  • Role: Abstract Class.
  • Purpose: Declares a factory method that returns a Product instance. It may also define additional methods that employ Product objects, but it does not explain how to build them. This course serves as a framework for developing products.
ConcreteCreator
  • Role: Subclass of Creator.
  • Purpose: Uses the factory technique to create customized Product instances. Defines the actual process of creating goods and guarantees that the correct Product type is instantiated. This class provides a concrete implementation for product generation.

    Here's a more extensive example that demonstrates the relationships

    interface Product
    {
    
    }
    
    class ConcreteProductA : Product
    {
    }
    
    class ConcreteProductB : Product
    {
    }
    
    abstract class Creator
    {
     public abstract Product FactoryMethod(string type);
    }
    
    class ConcreteCreator : Creator
    {
     public override Product FactoryMethod(string type)
     {
     switch (type)
     {
     case "A": return new ConcreteProductA();
     case "B": return new ConcreteProductB();
     default: throw new ArgumentException("Invalid type", "type");
     }
     }
    }

    This code demonstrates the Factory Method design pattern, in which a ConcreteCreator class determines which concrete Product type to construct based on input, separating object production from consumption.

    Understanding Factory Method Pattern using a real-time example

    Factory Method Pattern

    Who is what?

    The classes, interfaces, and objects in the above class diagram can be identified as follows:

    1. IFactory - Interface

    2. Scooter & Bike - Create product classes

    3. VehicleFactory - Creator

    4. ConcreteVehicleFactory - Concreate Creator

    C# - Sample Code

    using System;
    namespace Factory
    {
     /// <summary>
     /// The 'Product' interface
     /// </summary>
     public interface IFactory
     {
     void Drive(int miles);
     }
    
     /// <summary>
     /// A 'ConcreteProduct' class
     /// </summary>
     public class Scooter : IFactory
     {
     public void Drive(int miles)
     {
     Console.WriteLine("Drive the Scooter : " + miles.ToString() + "km");
     }
     }
    
     /// <summary>
     /// A 'ConcreteProduct' class
     /// </summary>
     public class Bike : IFactory
     {
     public void Drive(int miles)
     {
     Console.WriteLine("Drive the Bike : " + miles.ToString() + "km");
     }
     }
    
     /// <summary>
     /// The Creator Abstract Class
     /// </summary>
     public abstract class VehicleFactory
     {
     public abstract IFactory GetVehicle(string Vehicle);
    
     }
    
     /// <summary>
     /// A 'ConcreteCreator' class
     /// </summary>
     public class ConcreteVehicleFactory : VehicleFactory
     {
     public override IFactory GetVehicle(string Vehicle)
     {
     switch (Vehicle)
     {
     case "Scooter":
     return new Scooter();
     case "Bike":
     return new Bike();
     default:
     throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", Vehicle));
     }
     }
    
     }
     
     /// <summary>
     /// Factory Pattern Demo
     /// </summary>
     class Program
     {
     static void Main(string[] args)
     {
     VehicleFactory factory = new ConcreteVehicleFactory();
    
     IFactory scooter = factory.GetVehicle("Scooter");
     scooter.Drive(10);
    
     IFactory bike = factory.GetVehicle("Bike");
     bike.Drive(20);
    
     Console.ReadKey();
    
     }
     }
    }

    This code includes a Vehicle Factory that wraps vehicle production. This allows clients to access alternative vehicles (scooters or Bikes) without knowing their specific classes, promoting flexibility and loose coupling.

    Output

    Factory Pattern Demo Output

    Read More Articles Related to Design Pattern

    Summary

    The factory method design pattern provides a flexible and centralized approach to object production. It separates clients from the creation process, allowing dynamic object instantiation based on runtime requirements. This pattern allows for clearer, more maintainable code and promotes loose coupling, making it an invaluable tool for developers.

FAQs

Q1. What problem does Factory Method pattern solve?

The Factory Method pattern addresses the issue of creating objects without claiming the specific class of object that will be created, allowing subclasses to change the type of objects created. It encourages loose coupling by eliminating reliance on individual classes, which improves code flexibility and maintenance.

Q2. What is the use of factory design pattern in C#?

The Factory Design Pattern in C# is used to produce objects in a way that encapsulates their creation logic, enhancing flexibility and scalability by allowing subclasses to change the type of objects created.

Q3. What is the best use of factory design pattern?

The Factory Design Pattern is most useful when a class cannot predict the type of objects it will need to construct, allowing for dynamic instantiation while also fostering code decoupling and scalability.

Q4. What are the disadvantages of Factory pattern?

The disadvantages of the Factory pattern include increasing complexity as a result of the addition of new classes and interfaces, as well as potential difficulties in organizing and comprehending the codebase as the number of products and creators increases.

Q5. What is the main goal of the factory design pattern?

The Factory Design Pattern's primary purpose is to establish an interface for creating objects that allow subclasses to change the type of objects that are created, fostering flexibility and eliminating reliance on specific classes.
Share Article

Live Classes Schedule

Our learn-by-building-project method enables you to build practical/coding experience that sticks. 95% of our learners say they have confidence and remember more when they learn by building real world projects.
Software Architecture and Design Training Jul 28 SAT, SUN
Filling Fast
05:30PM to 07:30PM (IST)
Get Details
ASP.NET Core Certification Training Jul 28 SAT, SUN
Filling Fast
07:00AM to 09:00AM (IST)
Get Details
ASP.NET Core Project Aug 24 SAT, SUN
Filling Fast
07:00AM to 09:00AM (IST)
Get Details

Can't find convenient schedule? Let us know

About Author
Shailendra Chauhan (Microsoft MVP, Founder & CEO at Scholarhat by DotNetTricks)

Shailendra Chauhan is the Founder and CEO at ScholarHat by DotNetTricks which is a brand when it comes to e-Learning. He provides training and consultation over an array of technologies like Cloud, .NET, Angular, React, Node, Microservices, Containers and Mobile Apps development. He has been awarded Microsoft MVP 8th time in a row (2016-2023). He has changed many lives with his writings and unique training programs. He has a number of most sought-after books to his name which has helped job aspirants in cracking tough interviews with ease.
Accept cookies & close this