DEV Community

Patrick Schadler
Patrick Schadler

Posted on • Updated on

Factory Method Design Pattern

This post was originally published here.

Factory Method Design Pattern

In today's episode of Software Design Patterns you will learn everything about the Factory Method Design Pattern. The Factory Method is a creational pattern. That means that the pattern has something to do with object creation. There are different types of design patterns. The other types are structural and behavioral. Those types will have a dedicated blog post in the future. For reference - the last article covered the Singleton Design Pattern - which is also a creational pattern. All the examples, source code and unit tests are in this GitHub repository.

GitHub logo DonkeyKongJr / FactoryMethodPattern

This Repository hosts how a Factory Method Design Pattern could be used.

FactoryMethodPattern

Codacy Badge CircleCI

This Repository hosts how a Factory Method Design Pattern could be used.

You find an up-to-date description in the related blog post here. (Yet to come)

For any changes or updates please file a Pull Request.




What’s the purpose of the Factory Method Design Pattern?

The Factory Method is a very common pattern, but strongly misused. I have seen many examples where methods were named factory, but did something completely different. The quote below - taken from the Gang of Four - is very precise about the Factory Method. The Factory Method Design Pattern defines an interface for creating an object, but let sub classes decide which class to instantiate. Factory Method lets a class defer instantiating to sub classes. [1]

Don't fall into the trap and use it for everything. If you are not sure about when to use, you probably don't need it anyway.

How does the Factory Method looks like?

In the picture below you find the Unified Modeling Language (UML) diagram. Factory As mentioned at the beginning you find all the code examples in a working project on GitHub.

public interface ICar
{
    string GetName();
    void Accelerate();
    void Break();
}
Enter fullscreen mode Exit fullscreen mode
public class ElectricCar : ICar
{
    public int Speed { get; private set; }

    public string GetName()
    {
        return "Electric";
    }

    public void Accelerate()
    {
        Speed = Speed + 2;
    }

    public void Break()
    {
        if (Speed > 0)
        {
            Speed--;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
public class PetrolCar : ICar
{
    public int Speed { get; private set; }

    public string GetName()
    {
        return "Petrol";
    }

    public void Accelerate()
    {
        Speed++;
    }

    public void Break()
    {
        if (Speed > 0)
        {
            Speed--;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example we have an interface ICar.cs, which provides basic car operations like accelerate and break. In addition to that we have an GetName() method, were the concrete implementation should return the actual name of the car.

public class CarFactory
{
    public ICar CreateCar(string type)
    {
        if (string.Equals(type, "Petrol", StringComparison.OrdinalIgnoreCase))
        {
            return new PetrolCar();
        }

        if (string.Equals(type, "Electric", StringComparison.OrdinalIgnoreCase))
        {
            return new ElectricCar();
        }

        throw new NotSupportedException($Car Type '{type}' is not supported);
    }
}
Enter fullscreen mode Exit fullscreen mode

Our Factory, called CarFactory.cs, is responsible for creating instances of concrete cars. We provide a dedicated CreateCar(string type) method, where the desired type can be passed as an argument. The method maps the type to a concrete implementation. This can be done via multiple if clauses or a switch statement. Anyway, if there is no matching type we throw an NotSupportedException to make it clear that the factory does not support the desired type. To see the proper use of the CarFactory look into the test project.

public class CarFactoryTest
{
    [Theory]
    [InlineData("Electric")]
    [InlineData("electric")]
    [InlineData("eLeCtriC")]
    public void ShouldCreateElectricCarInstance(string type)
    {
        var carFactory = new CarFactory();
        var car = carFactory.CreateCar(type);

        car.Should().BeOfType<ElectricCar>();
        car.GetName().Should().Be("Electric");
    }

    [Theory]
    [InlineData("Petrol")]
    [InlineData("petrol")]
    [InlineData("pEtRoL")]
    public void ShouldCreatePetrolCarInstance(string type)
    {
        var carFactory = new CarFactory();
        var car = carFactory.CreateCar(type);

        car.Should().BeOfType<PetrolCar>();
        car.GetName().Should().Be("Petrol");
    }

    [Theory]
    [InlineData("hans")]
    [InlineData("car")]
    [InlineData("electricpetrol")]
    public void ShouldThrowNotSupportedExceptionWhenTypeIsInvalid(string type)
    {
        var carFactory = new CarFactory();
        Action getCar = () => carFactory.CreateCar(type);

        getCar.Should().ThrowExactly<NotSupportedException>();
    }
}
Enter fullscreen mode Exit fullscreen mode

If you have any questions or comments feel free to leave them below. That’s it. Happy coding as always.

References[1] -Design patterns, software engineering, object-oriented programming

Top comments (7)

Collapse
 
koski84 profile image
Koski84 • Edited

The quote below - taken from the Gang of Four - is very precise about the Factory Method. The Factory Method Design Pattern defines an interface for creating an object, but let sub classes decide which class to instantiate. Factory Method lets a class defer instantiating to sub classes.

Your code doesn't follow this. This is factory method pattern:

interface CarFactory
{
    ICar CreateCar();
}

class ElectricCarFactory : CarFactory
{
    ICar CreateCar()
    {
        // logic to create a electric car
    }
}

class PetrolCarFactory : CarFactory
{
    ICar CreateCar()
    {
        // logic to create a petrol car
    }
}
Collapse
 
patzistar profile image
Patrick Schadler

Chapeau, this is spot on! I am guilty of adjusting the definition ever so slightly to my preferences, but you are right. Thank you for pointing that out.

Collapse
 
nineismine profile image
nineismine

Great Article! I have been working on implementing a Factory method for parsing files which all have different parse methods. Essentially we pass in an unparsed file type the factory looks at a specific part of the file (which tells it what kind of file it is dealing with) and then we return the proper parsed file result! This lines up with my understanding of it!

Collapse
 
patzistar profile image
Patrick Schadler

Thank you for your insights. As you said we both share the same understanding of it 🤝

Collapse
 
euankennedy profile image
Euan

Nice one, thanks. I’d have expected a method called “break” to do something more destructive than just decrement the speed! 😜

Collapse
 
patzistar profile image
Patrick Schadler

Haha, I really waited for this reply 😅 Maybe version 2 could be more destructive and dramatic 🔚

Collapse
 
patzistar profile image
Patrick Schadler

You‘re right. An enumeration would be totally fine as well. I leave this to personal preference, this particular example is to demonstrate a very simplified usage.