2

Im looking to this example to understand the use of factory pattern.

I'm really amator in this field so excuse my silly question.

My problem is that i don't see the use of the factory pattern which return us the interface that we can inject it directly when we need to use it.

In the example above I would do something like this:

public class Program
{
    // register the interfaces with DI container in a separate config class (Unity in this case)
    private readonly IShippingStrategy _shippingStrategy;

    public Program(IShippingStrategy shippingStrategy)
    {
        _shippingStrategy= shippingStrategy;
    }

    public int DoTheWork(Order order)
    {
        // assign properties just as an example
        order.ShippingMethod = "Fedex";
        order.OrderTotal = 90;
        order.OrderWeight = 12;
        order.OrderZipCode = 98109;

        int shippingCost = _shippingStrategy.CalculateShippingCost(order);

        return shippingCost;
    }
}

Instead of injecting the factory :

public class Program
{
    // register the interfaces with DI container in a separate config class (Unity in this case)
    private readonly IShippingStrategyFactory _shippingStrategyFactory;

    public Program(IShippingStrategyFactory shippingStrategyFactory)
    {
        _shippingStrategyFactory = shippingStrategyFactory;
    }

    public int DoTheWork(Order order)
    {
        // assign properties just as an example
        order.ShippingMethod = "Fedex";
        order.OrderTotal = 90;
        order.OrderWeight = 12;
        order.OrderZipCode = 98109;

        IShippingStrategy shippingStrategy = _shippingStrategyFactory.GetShippingStrategy(order);
        int shippingCost = shippingStrategy.CalculateShippingCost(order);

        return shippingCost;
    }
}

Why taking the bruden to create a factory (thus adding an extra layer) when we can inject the interface directly to wherever we need to use it ?

Soufien Hajji
  • 477
  • 1
  • 8
  • 24
  • 1
    Please explain how you would get the injected shipping strategy to depend on the order, as is evident from the parameter to the factory method. – Lasse V. Karlsen Dec 03 '18 at 14:36
  • 1
    Dependency Injection is a generic concept, typically DI is accomplished through the use of a DI Framework, which is essentially just a generic factory pattern that allows for a very flexible configuration facility. So, in essence, a DI Framework *IS* a factory. But not all factories are DI Frameworks. Typically one refers to a factory to mean a custom factory, customized for the specific situation. Some DI Frameworks even allow you to specify custom factories to control the logic even more finely. – Erik Funkenbusch Dec 03 '18 at 15:07

2 Answers2

4

I think you don't want just another article about the factory pattern but a short comprehensive answer. So, I'd like to focus on two things.

More flexibility

Most commonly, you'd set up your composition root where you basically say ...

"if anyone wants IAnyService, he should get MyAnyServiceImplementation".

This is fixed for your application. Once set up, your dependency injection container will serve the class instances you registered but you should not try to re-configure that container again. That's perfect for startup flexibility like registering implementation for data access components by the application's configuration, for example. Say ...

"if anyone wants IUserRepository, he should get MsSqlUserRepository because we are working with MSSQL server".

Of course, having that "immutable" composition root limits the possibilities to choose an implementation in runtime depending of the applications' state.

Instead you can inject a class which decides on a current state which service implementation to choose. Data validation is a typical scenario for that pattern because there might be different rules for different entities on your system. The buzzword here is "rule pattern" or "strategy pattern".

Lifetime control

Think of a long-living class instance like a view (user interface) or any class attached to it (like a viewmodel or a controller). As long as a user is active on a view, the class is alive. By injecting a class instance to the constructor of the view controller, for example, you hold an active instance of it as long as the view lives.

Let's say you want to use a data repository to connect to a database for example. These database access calls should be short and you do not want to keep connections open for a long time. With a repository factory, you could control the lifetime very precisely and make sure that the class is removed after it has been used:

using (var repository = new _factory.CreateRepository(...))
{
    return repository.GetAnything();
}

With this, a very lightweight class - the factory - gets injected and lives as long as the view controller lives. The heavy classes - the connection things - should not live long and are just created when needed.

In fact, chances are that the repository is not instantiated at all if there's no requirement to load the data (because of an upfront cache hit, for example). If you would have injected the repository directly, you'd guarantee that one long living instance lives in memory in every case.

Waescher
  • 5,361
  • 3
  • 34
  • 51
  • Great explanation. I just want to highlight something you said in "More flexibility" section. Let's say that I have `IUserRepository` interface that you talked about. For me the advantage that we can get from using factory pattern is that we have the capacity to use various data access components in the same application. For example if we have `MsSqlUserRepository` and `AzurelUserRepository` we can use them both in the same application using factory pattern which is impossible if we directly inject `IUserRepository` right ? – Soufien Hajji Dec 03 '18 at 15:36
  • 2
    Mmmh ... not quite. You can use them both without a factory as well. However, you can make the decision only once at application startup. If you are configured to use MSSQL, use `MsSqlUserRepository`, if you are configured to sync with Azure, use `AzureUserRepository`. Once the process is running, you have to live with it. Having a factory enables you to switch between those two in runtime, but I think data access is not the best use case for it because it's not likely to be that generic. Maybe you meant the same thing, I'm not exactly sure if I got "in the same application" right. – Waescher Dec 03 '18 at 15:46
  • 1
    Very good explanation ! I know that it's unlikely to use different data access in the same application i just want to understand the logic here :). Again excellent explanation and thank you very much ! – Soufien Hajji Dec 03 '18 at 15:51
1

If you check the code for the factory you can see that depending on the ShippingMethod of the order a different implementation of the IShippingStrategy is returned by the factory. Since the ShippingMethod is only known once DoTheWork has been called it's impossible to inject the right implementation when the class is constructed (and the same class might even need different implementations for different orders).

  • So in a nutshell we use the factory pattern when we don't know which interface implementation to use when consuming it ? I though that when injecting directly the interface we should also indicate (in another place which implementation to use) but i guess that this is wrong – Soufien Hajji Dec 03 '18 at 14:43
  • 4
    If you can bind your service to a specific dependency, you can usually do so using the registrations, in which case you can use DI. But if the correct service depends on the data involved, a factory pattern is the way to go. – Lasse V. Karlsen Dec 03 '18 at 14:47
  • great ! i never knew there was something called registration in DI. Thank you very much ! – Soufien Hajji Dec 03 '18 at 15:39