Hello everyone, and welcome to .NET Core Central. In this blog post, I am going to walk through the Factory Method design pattern. The Factory Method design pattern is a creational design pattern.
The main intent of the Factory Method design pattern is to allow the creation of an object without exposing the creation logic to the client. And it is one of the design patterns from the Gang of Four design patterns.
Factory Method Example
Let us take an example and walk through exactly the definition of the Factory Method design pattern. For example, let us consider the situation of a website which is responsible for selling different products. And for selling products, the website needs to show a catalog.
And let us say that one of the catalogs is for lawnmowers. Now there can be different types of lawnmowers. For example:
- Firstly, there can be lawnmowers that runs on diesel
- Secndly, there are lawn mowers that uses electric to run
- Finally, there are manual lawnmower as well
The code
So now the requirement is when the user selects the type of lawnmower, we should be showing the lawnmower associated with that. And the best way to implement that is to have an ILwanmowerCatalog and different classes for different types of lawnmower catalogs.
Hence we will have an interface called ILawnmowerCatalog
. And this interface has a method called GetLawnmowers
, which returns an array of an object type Lawnmower
.
namespace FactoryMethodPattern.Demo
{
public interface ILawnmowerCatalog
{
Lawnmower[] GetLawnmowers();
}
}
namespace FactoryMethodPattern.Demo
{
public class Lawnmower
{
public string Name { get; set; }
}
}
For the simplicity of the example, for the Lawnmower
class itself, I will have a single property Name
of type string
.
The Lawnmower classes
Next, we will create three types of lawnmower catalog classes. And these classes will be responsible for returning each type of lawnmower.
namespace FactoryMethodPattern.Demo
{
public class DieselLawnmowerCatalog : ILawnmowerCatalog
{
public Lawnmower[] GetLawnmowers()
{
return new[] { new Lawnmower { Name = "I am Diesel Lawnmower" } };
}
}
public class ElectricLawnmowerCatalog : ILawnmowerCatalog
{
public Lawnmower[] GetLawnmowers()
{
return new[] { new Lawnmower { Name = "I am Electric Lawnmower" } };
}
}
public class ManualLawnmowerCatalog : ILawnmowerCatalog
{
public Lawnmower[] GetLawnmowers()
{
return new[] { new Lawnmower { Name = "I am Manual Lawnmower" } };
}
}
}
For the simplicity of the example, I am just returning a string for each of the lawnmower types.
The Controller
Now we will create a new controller class with the name LawnmowerCatalogController
. There will be a single GET method in this controller class. And this GET method is responsible for returning all the lawnmowers associated to a type.
using Microsoft.AspNetCore.Mvc;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace FactoryMethodPattern.Demo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class LawnmowerCatalogController : ControllerBase
{
private readonly ILawnmowerCatalog lawnmowerCatalog;
public LawnmowerCatalogController(ILawnmowerCatalog lawnmowerCatalog)
{
this.lawnmowerCatalog = lawnmowerCatalog;
}
// GET api/<LawnmowerCatalogController>/5
[HttpGet]
public IEnumerable<Lawnmower> Get(string type)
{
return null;
}
}
}
One way of doing it is getting an array of all the lawnmowers, and then we can iterate through the lawnmower and check the type name. And if the type name matches the type string passed in the parameter, we will send those catalogs in response.
But this is not a very elegant solution. And this is where the factory method comes into play.
How to create Factory Method
The standard way of creating a factory method is through a factory method class. So here we can create a class and we can call it as LawnmowerCatalogFactory. The LawnmowerCatalogFactory will be responsible for returning a type of lawnmower catalog class based on the type name sent by the caller.
namespace FactoryMethodPattern.Demo
{
public interface ILawnmowerCatalogFactory
{
ILawnmowerCatalog CreateCatalog(string type);
}
}
namespace FactoryMethodPattern.Demo
{
public class LawnmowerCatalogFactory : ILawnmowerCatalogFactory
{
public ILawnmowerCatalog CreateCatalog(string type)
{
return type switch
{
"Diesel" => new DieselLawnmowerCatalog(),
"Electric" => new ElectricLawnmowerCatalog(),
_ => new ManualLawnmowerCatalog(),
};
}
}
}
The factory method above will take the type of the catalog. And will implement a switch pattern to return the respective catalog based on the type.
Change in the controller class
Next, we will change the controller class. So instead of taking ILawnmowerCatalog as a dependency, it will take ILawnmowerCatalogFactory as a dependency.
And inside of the GET method, it will use the ILawnmowerCatalogFactory to find an appropriate lawnmower catalog, and return the corresponding lawnmowers.
using Microsoft.AspNetCore.Mvc;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace FactoryMethodPattern.Demo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class LawnmowerCatalogController : ControllerBase
{
private readonly ILawnmowerCatalogFactory lawnmowerCatalogFactory;
public LawnmowerCatalogController(ILawnmowerCatalogFactory lawnmowerCatalogFactory)
{
this.lawnmowerCatalogFactory = lawnmowerCatalogFactory;
}
// GET api/<LawnmowerCatalogController>/5
[HttpGet]
public IEnumerable<Lawnmower> Get(string type)
{
return lawnmowerCatalogFactory.CreateCatalog(type).GetLawnmowers();
}
}
}
Adding dependencies
Once the code is ready, now I will add the dependencies to the dependency injection container inside of the Program
class (since I am using .NET 6 and C# 10).
I will add the interface/class ILawnmowerCatalogFactory/LawnmowerCatalogFactory
as a singleton instance.
using FactoryMethodPattern.Demo;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<ILawnmowerCatalogFactory, LawnmowerCatalogFactory>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Running the application
Now if I run this application, I can use the Swagger UI to try it out. And I can try electric as the type and execute it. And in the response, I will see “I am Electric Lawnmower” as expected.
This is the standard implementation of the factory method, where we create a factory class. And then create a method that is responsible for creating the underlying instance that is needed.
One other advantage of using an interface along with the factory class for the factory method itself is that it is very easy to unit testable. That is because it’s very easy to mock the ILawnmowerCatalogFactory
.
Alternate Implementation of Factory Method
There is another alternative to using a factory class in C#. And I personally prefer this alternative.
In this alternative, instead of creating this factory class and an interface, we can change the implementation a little bit here. And instead of the factory class, we can have a lambda function.
So for this implementation, in the controller class, instead of injecting the ILawnmowerCatalogFactory
, we will inject a lambda function, which will return ILawnmowerCatalog
based on the type name.
using Microsoft.AspNetCore.Mvc;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace FactoryMethodPattern.Demo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class LawnmowerCatalogController : ControllerBase
{
private readonly Func<string, ILawnmowerCatalog> lawnmowerCatalogFactory;
public LawnmowerCatalogController(Func<string, ILawnmowerCatalog> lawnmowerCatalogFactory)
{
this.lawnmowerCatalogFactory = lawnmowerCatalogFactory;
}
// GET api/<LawnmowerCatalogController>/5
[HttpGet]
public IEnumerable<Lawnmower> Get(string type)
{
return lawnmowerCatalogFactory(type).GetLawnmowers();
}
}
}
Next, we will change the implementation in the Program class for the dependency injection. And instead of adding the ILawnmowerCatalogFactory to the dependency injection container, I will add the lambda function.
using FactoryMethodPattern.Demo;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<Func<string, ILawnmowerCatalog>>(type => {
return type switch
{
"Diesel" => new DieselLawnmowerCatalog(),
"Electric" => new ElectricLawnmowerCatalog(),
_ => new ManualLawnmowerCatalog(),
};
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
In this implementation of the factory method, the factory is inside of the dependency injection container itself, rather than a separate class.
This is where usually I prefer to keep the code, but you can create a separate class and keep the implementation there.
Now if the run this application, I am going to see the exact same response as before.
Conclusion
This is one of the very interesting and handy design patterns. Because there are some times where you might want to create an instance based on some external variable. And in that case, your only friend is a factory method design pattern.
A Youtube video for this implementation is here.