Skip to main content

Design Patterns: Factory Method

Let’s continue our series on design patterns with the Factory Method. Like the Builder or Singleton patterns we covered in previous posts, the Factory Method is also one of the creational patterns. It introduces a slightly more complex approach, offering a higher level of abstraction for object creation. Additionally, it helps decouple the object creation process from the rest of the application.

It can be represented through the following components:

  • Abstract object, which represents the base class for the objects that we want to create
  • Concreate objects, classes that inherit the given base class
  • Creator, abstraction of the classes resposible for the object creation
  • Concreate creators, classes that inherit and implement given creator class
  • Client or Consumer side, parts of the application where we call objects creation
Bellow, we will show all these parts in one simple example.

using System;

// abstract object
abstract class Engine
{
    public abstract void Start();
}

// Concrete object, concrete Engine classes
class DieselEngine: Engine
{
    public override void Start()
    {
        Console.WriteLine("Starting diesel engine!");
    }
}

class PetrolEngine: Engine
{
    public override void Start()
    {
        Console.WriteLine("Starting petrol engine!");
    }
}


// Creator
abstract class EngineFactory
{
    public abstract Engine CreateEngine();
}

// Concrete Creators
class DieselEngineFactory : EngineFactory
{
    public override Engine CreateEngine()
    {
        return new DieselEngine();
    }
}

class PetrolEngineFactory : EngineFactory
{
    public override Engine CreateEngine()
    {
        return new PetrolEngine();
    }
}


// Client code
class Program
{
    static void Main(string[] args)
    {
        EngineFactory factory;

        // Let's assume user chooses the engine type at runtime.
        Console.WriteLine("Enter the type of engine (diesel/petrol):");
        string choice = Console.ReadLine()?.ToLower();

        if (choice == "diesel")
        {
            factory = new DieselEngineFactory();
        }
        else if (choice == "petrol")
        {
            factory = new PetrolEngineFactory();
        }
        else
        {
            Console.WriteLine("Invalid choice!");
            return;
        }

        Engine engine = factory.CreateEngine();
        engine.Start();
    }
}

In the example above, we can see the simple case where this pattern could be applied. Now, when we want to add a new engine type, we just need to extend existing logic with new engine type, without change of existing code resposible for Diesel or Petrol engines. Here we can see the flexibility of such approach, but of course, in some cases this can be the overhead. Examples of the overhead could be when we have the cases for simple object creation or when we know that extension of existing objects creation won't happen in the future. In such cases, this pattern would be just an overengineering and not necessary at all.

Comments

Popular posts from this blog

Design Patterns: Strategy

The Strategy Pattern is a behavioral design pattern that defines a family of algorithms, encapsulates each one, and makes them interchangeable. This pattern allows the algorithm to be selected at runtime, providing flexibility in designing software. It’s particularly useful when you have multiple ways of performing a task, and you want to choose the implementation dynamically without altering the client code. When To Use It? You Have Multiple Algorithms or Behaviors. Use it when you have a need for muplitple ways of performing a task, and you want to make these implementations interchangeable. Examples: Different sorting algorithms, payment methods, discount calculations... You Want to Eliminate Conditional Logic.  If you find yourself writing large if-else or switch statements to decide which algorithm to use, this pattern can simplify and clean up your code. Examples: A game character with different attack styles  You Need Runtime Flexibility.  Use this pattern if the ...

Design Patterns: Builder

This is also, like a Singleton , one of the creational design patterns. It provides the way of creating complex objects step by step by simple chaining and every particular step is independent of other steps. Let us dive into the real example of usage. For showing purpose we have created an example in C# which creates simple SQL queries using described pattern.  using System; using System.Text; namespace BuilderPatternExample { public interface ISqlQueryBuilder { ISqlQueryBuilder Select(string columns); ISqlQueryBuilder From(string table); ISqlQueryBuilder Where(string condition); ISqlQueryBuilder OrderBy(string columns); string Build(); } public class SelectQueryBuilder : ISqlQueryBuilder { private readonly StringBuilder _queryBuilder; public SelectQueryBuilder() { _queryBuilder = new StringBuilder(); } public ISqlQueryBuilder Select(string columns) { ...

Design Patterns: Singleton

Tyipically the first design pattern most people learn, often wrongly ☺ To give an introduction, we can say that singleton is one of the creational design patterns which ensures only one class instance with single point of access thru entire application.  Because it is relatively simple to implement, the Singleton pattern is sometimes misapplied in situations where it is not the most suitable choice. When to use it? Here are the few examples of corrent usage of singleton: Configuration Management  Centralized configuration settings for consistent use thru entire application Caching Maintaning  Single istance of cached objects for easy and fast acces Logging  Ensure unified mechanism to avoid duplication of log files, formats, etc Global State Management  Centralized management of the state which is needed to be shared accross the application Resource sharing  Thread pools, database connection, I/O operations When not to use it? On the other hand, here are fe...