Factory Method With Di and Ioc

Factory method with DI and IoC

Having a switch case statement inside of a factory is a code smell. Interestingly, you don't seem to be focusing on solving that issue at all.

The best, most DI friendly solution for this scenario is the strategy pattern. It allows your DI container to inject the dependencies into the factory instances where they belong, without cluttering up other classes with those dependencies or resorting to a service locator.

Interfaces

public interface ICarFactory
{
ICar CreateCar();
bool AppliesTo(Type type);
}

public interface ICarStrategy
{
ICar CreateCar(Type type);
}

Factories

public class Car1Factory : ICarFactory
{
private readonly IDep1 dep1;
private readonly IDep2 dep2;
private readonly IDep3 dep3;

public Car1Factory(IDep1 dep1, IDep2 dep2, IDep3 dep3)
{
this.dep1 = dep1 ?? throw new ArgumentNullException(nameof(dep1));
this.dep2 = dep2 ?? throw new ArgumentNullException(nameof(dep2));
this.dep3 = dep3 ?? throw new ArgumentNullException(nameof(dep3));
}

public ICar CreateCar()
{
return new Car1(this.dep1, this.dep2, this.dep3);
}

public bool AppliesTo(Type type)
{
return typeof(Car1).Equals(type);
}
}

public class Car2Factory : ICarFactory
{
private readonly IDep4 dep4;
private readonly IDep5 dep5;
private readonly IDep6 dep6;

public Car2Factory(IDep4 dep4, IDep5 dep5, IDep6 dep6)
{
this.dep4 = dep4 ?? throw new ArgumentNullException(nameof(dep4));
this.dep5 = dep5 ?? throw new ArgumentNullException(nameof(dep5));
this.dep6 = dep6 ?? throw new ArgumentNullException(nameof(dep6));
}

public ICar CreateCar()
{
return new Car2(this.dep4, this.dep5, this.dep6);
}

public bool AppliesTo(Type type)
{
return typeof(Car2).Equals(type);
}
}

Strategy

public class CarStrategy : ICarStrategy
{
private readonly ICarFactory[] carFactories;

public CarStrategy(ICarFactory[] carFactories)
{
this.carFactories = carFactories ?? throw new ArgumentNullException(nameof(carFactories));
}

public ICar CreateCar(Type type)
{
var carFactory = this.carFactories
.FirstOrDefault(factory => factory.AppliesTo(type));

if (carFactory == null)
{
throw new InvalidOperationException($"{type} not registered");
}

return carFactory.CreateCar();
}
}

Usage

// I am showing this in code, but you would normally 
// do this with your DI container in your composition
// root, and the instance would be created by injecting
// it somewhere.
var strategy = new CarStrategy(new ICarFactory[] {
new Car1Factory(dep1, dep2, dep3),
new Car2Factory(dep4, dep5, dep6)
});

// And then once it is injected, you would simply do this.
// Note that you could use a magic string or some other
// data type as the parameter if you prefer.
var car1 = strategy.CreateCar(typeof(Car1));
var car2 = strategy.CreateCar(typeof(Car2));

Note that because there is no switch case statement, you can add additional factories to the strategy without changing the design, and each of those factories can have their own dependencies that are injected by the DI container.

var strategy = new CarStrategy(new ICarFactory[] {
new Car1Factory(dep1, dep2, dep3),
new Car2Factory(dep4, dep5, dep6),
new Car3Factory(dep7, dep8, dep9)
});

var car1 = strategy.CreateCar(typeof(Car1));
var car2 = strategy.CreateCar(typeof(Car2));
var car3 = strategy.CreateCar(typeof(Car3));

How to set up DI / IoC and/or Factory pattern design in C#

I am not really sure if I understood your design, but the general approach could be the following:

  1. Think about the behavioural and structural elements all client connection handlers have in common and either extract a base class or interface. For example, there might be a Connect() or Send(ICommand) method.

  2. Think about the structural and behavioural elements of other components in your design, e.g. commands or loggers or whatever. Some sort of base class library will be the result.

  3. Decide how you want to instantiate concrete instances of connection types. If the decission about the connection type relies on a set of parameters, you can utilize a factory. The factory will take a set of parameters and return a connection type instance. The factory could fulfill an interface itself and thus be resolved by the IoC itself (Abstract Factory).

The factory itself could just instantiate concrete classes, but your connection classes may utilize constructor-based injection to get access to other components (loggers, helpers, whatever), thus your factory could rely on the IoC Container, something like:

Update: As Michael pointed out, passing the container to the factory might be convenient but hides the concrete dependencies the factory has. While it might be okay with smaller applications, a better approach is passing all connection-type dependencies to the Factory which instantiates concrete instances.

class StandardConnectionFactory : IConnectionFactory
{
private readonly IContainer iocContainer;

public StandardConnectionFactory(IContainer iocContainer)
{
this.iocContainer = iocContainer;
}

public IConnection Create(string param1, int param2, ...)
{
if (...) return iocContainer.Resolve<IFancySshConnection>();
else return iocContainer.Resolve<IAnotherConnection>();
}
}

  1. If the decission about which connection type to use rather relies on some simple enum or string (e.g. the user decides what connection to use by a command line param), some IoC Containers (e.g. Autofac) allow to register a class with a name and resolve by that name. In that case, you do not need a factory and might end up with something like:

(Pseudo-Code)

// Registration Process
containerBuilder.Register<FancySshConnection>().For<IConnection>().WithName("ssh");
containerBuilder.Register<FancyFtpConnection>().For<IConnection>().WitName("ftp");

// Resolve
var connection = container.ResolveByName("ftp")

  1. When you finished to implement a way to instantiate connections, either by an explicit factory (3) or some built-in instantiation (4), the dependencies of the connection type known to your IoC container will be injected automatically. For example, the above call to iocContainer.Resolve<IFancySshConnection>(); will instantiate the concrete connection type, look at its constructor, try to resolve each parameter, inject them, and so on. It will climb up the dependency tree as long as it finds dependencies that were registered before.
    So basically all you have to do is registering your base class components (2).

  2. If things get bigger and more complex, you may end up with alof of registrations. Some IoC containers (I stick to the Autofac example because I really like Autofac) provide an easy way to split registrations into modules. This allows to distribute the process of registration into different assemblies.

Using a Strategy and Factory Pattern with Dependency Injection

There are a few ways of doing this, but the way I prefer is to inject a list of available strategies into your factory, and then filtering them to return the one(s) you're interested in.

Working with your example, I'd modify IShippingStrategy to add a new property:

public interface IShippingStrategy
{
int CalculateShippingCost(Order order);
string SupportedShippingMethod { get; }
}

Then I'd implement the factory like so:

public class ShippingStrategyFactory : IShippingStrategyFactory
{
private readonly IEnumerable<IShippingStrategy> availableStrategies;

public ShippingStrategyFactory(IEnumerable<IShippingStrategy> availableStrategies)
{
this.availableStrategies = availableStrategies;
}

public IShippingStrategy GetShippingStrategy(Order order)
{
var supportedStrategy = availableStrategies
.FirstOrDefault(x => x.SupportedShippingMethod == order.ShippingMethod);
if (supportedStrategy == null)
{
throw new InvalidOperationException($"No supported strategy found for shipping method '{order.ShippingMethod}'.");
}

return supportedStrategy;
}
}

The main reason I like using it this way is that I never have to come back and modify the factory. If ever I have to implement a new strategy, the factory doesn't have to be changed. If you're using auto-registration with your container, you don't even have to register the new strategy either, so it's simply a case of allowing you to spend more time writing new code.

Should I choose Dependency Injection or Factory Pattern

Lets look at the difference between them.

With DI, objects are created externally and "injected" for use by the client object.
Injection is commonly done via constructor.

However, in complex situations, its common to inject a DI container to create the dependency objects, including all sub-dependencies. So it then looks like Abstract Factory!

With Abstract Factory, an instance of a concrete Factory class is injected and the dependency objects are instantiated by the client object.

So DI and Abstract Factory are pretty much the same, when you consider that in both cases, factory objects are passed to the client to enable it to create its dependencies.

In simple cases only, the dependent objects are created externally and passed to the client object. This is how Strategy Pattern works.

Since DI containers are so prevalent now, and used so extensively in frameworks, they have effectively replaced Abstract Factory, at least as a pattern that is frequently spoken about. DI containers are vastly more complex entities than were ever envisaged for Abstract Factories (I believe).

So there is no best practice!

C# Difference between factory pattern and IoC

The factory pattern:
the object which needs a reference to a service, should know about the factory that creates the Service:

public class BLLObject 
{
public IDal DalInstance { get; set; }

public BLLObject()
{
DalInstance = DalFactory.CreateSqlServerDal();
}
}

The Ioc Pattern (or Dependency Injection) :

the object only needs to declare its need to the service, using any aspects of the Ioc Pattern (Constructor, setter, or interface ... etc)
and the container will try to fulfill this need:

public class BLLObject 
{
public IDal DalInstance { get; set; }

public BLLObject(IDal _dalInstance)
{
DalInstance = _dalInstance;
}
}

which means that in the factory pattern, the object decides which creation method (by choosing a specific concrete factory) to use, but the in the Ioc pattern, it is up to the container to choose.

of course this is not the only deference, but this is what is in my mind for the time being.
correct me please if I'm wrong ?

.Using a Factory Pattern with NET Core 3.1 Dependency Injection

This requires restart after changing the configuration, but I see no problem in doing it like this.

public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(Configuration);

services.AddScoped<IMassTransitRabbitMqTransport, MassTransitRabbitMqTransport>();
services.AddScoped<IMassTransitAzureServiceBusTransport, MassTransitAzureServiceBusTransport>();

var messageProvider = Configuration.GetConfig("MessageService", "Messaging_Service");
switch(messageProvider)
{
case "AzureServiceBus":
services.AddScoped<IMessagingService, MassTransitAzureServiceBusMessagingService>();
break;
case "RabbitMq":
services.AddScoped<IMessagingService, MassTransitRabbitMqMessagingService>();
break;
default:
throw new ArgumentException("Invalid message service");
};

services.AddControllers();
}

Other note

I noticed that you supplied both the concrete type and a factory:

services.AddScoped<IMessagingService, MassTransitAzureServiceBusMessagingService>(s => s.GetService<MassTransitAzureServiceBusMessagingService>());

I think it should be:

services.AddScoped<IMessagingService>(s => s.GetService<MassTransitAzureServiceBusMessagingService>());

Not sure it it makes a difference.

UPDATE Jan 2021
Recently I had to do this myself and came up with this solution:

public static IServiceCollection ConfigureEventBus(this IServiceCollection services, IConfiguration configuration)
{
var queueSettings = new QueueSettings();
configuration.GetSection("QueueSettings").Bind(queueSettings);

if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
{
services.AddMassTransit(x =>
{
x.UsingAzureServiceBus((context, cfg) =>
{
cfg.Host(queueSettings.HostName);
});
});
}
else
{
services.AddMassTransit(x =>
{
x.UsingRabbitMq((context, cfg) =>
{
cfg.ConfigureEndpoints(context);
cfg.Host(queueSettings.HostName, queueSettings.VirtualHost, h =>
{
h.Username(queueSettings.UserName);
h.Password(queueSettings.Password);
});
});
});
}

services.AddMassTransitHostedService();
services.AddSingleton<IEventBus, MassTransitEventBus>();

return services;
}

C# - Ninject, IoC and factory pattern

If your IFeature implementations does not have other dependencies than using your approach is fine and very simple.
For example lets say you have 2 implementations of IFeature - SomeFeature and OtherFeature that both have parametersless constructor.
Your factory implementation as you suggest would be something like that:

public class FeatureFactory: IFeatureFactory
{
IFeature CreateFeature(string input)
{
if(input=="SomeFeature")
{
return new SomeFeature();
}
else
{
return new OtherFeature ();
}
}
}

However when your IFeature implementations have their own dependencies using this approach you lose the point of using Ninject and IoC.

For example lets say That SomeFeature looks something like that:

public class SomeFeature : IFeature
{
private readonly IDependency1 _dependency1;
private readonly IDependency2 _dependency2;

public SomeFeature (IDependency1 dependency1, IDependency2 dependency2)
{
_dependency1=dependency1;
_dependency2=dependency2;
}

string execFeature()
{
//Some code here...
}
}

And OtherFeature is similar...

 public class OtherFeature: IFeature
{
private readonly IDependency1 _dependency1;
private readonly IDependency2 _dependency2;

public OtherFeature(IDependency1 dependency1, IDependency2 dependency2)
{
_dependency1=dependency1;
_dependency2=dependency2;
}

string execFeature()
{
//Some code here...
}
}

Now your factory would become something like that:

 public class FeatureFactory: IFeatureFactory 
{
IFeature CreateFeature(string input)
{
if(input=="SomeFeature")
{
return new SomeFeature(new Dependency1Implementation(), new Dependency2Implementation());
}
else
{
return new OtherFeature(new Dependency1Implementation(), new Dependency2Implementation());
}
}
}

This is the place when you can use the power of the ninject.extensions.factory
by using the container to solve this dependencies for you.(This dependencies can have their own dependencies and it can get messy very quickly).

As other mentioned you can bind every IFeature implementation using named binding.

Bind<IFeature>().To<SomeFeature>().Named("SomeFeature");
Bind<IFeature>().To<OtherFeature>().Named("OtherFeature");

Of Course you should bind other dependencies as well

Bind<IDependency1>().To<Dependency1Implementation>();
Bind<IDependency2>().To<Dependency2Implementation>();

And then bind the IFeatureFactory to Factory using the factory extension.

Bind<IFeatureFactory>().ToFactory();

What you have to do is create factory method for each of your IFeature implementations in IFeatureFactory and call it Get... according to the Feature named binding.

public interface IFeatureFactory
{
IFeature GetSomeFeature();
IFeature GetOtherFeature();
}

Now ninject will implement(!) this class for you and know which implementation to choose for each method.(There is no need for service locator....)

You can use switch statement over the input in your client to choose which factory method to call or you can wrap it in some provider class that will have the switch statement in it, in both cases you will not have to do the 'new' for IFeature implementations yourself.

Of Course you can pass parameters to the implementations constructors by the factory methods if you need to and other more complex things.


I suggest you to read this for further information.

Edit

I would like to emphasis you don't have to write factory method for each implementation, you can use the same method for all (It is possible but more complex).
To do it you will need to create custom instance provider to detect which implementation to instantiate (according to the factory parameters for example), more about this in the link above and here.

Abstract factory pattern on top of IoC?

As you have already figured out, Dependency Injection (DI) itself is only a collection of patterns and techniques.

At the root of the application we wire up all necessary object graphs. This place is called the Composition Root, and we can use a DI Container to do this wiring for us, or we can do it manually (Pure DI).

The point is that there's only one place in your application where there's a strong reference to a particular piece of technology (your DI Container). The rest of the app is blissfully unaware of how the object graph was wired up - all that matters is that all required dependencies were correctly injected (and you can use Constructor Injection with Null Guards to guarantee that this is so).

The Abstract Factory pattern is a very useful pattern when it comes to DI. In essence, use Abstract Factory when:

  • You need to supply one or more parameters only known at run-time before you can resolve a dependency.
  • The lifetime of the dependency is conceptually shorter than the lifetime of the consumer.

Examples and more information is available here:

  • Is there a pattern for initializing objects created via a DI container
  • Can't combine Factory / DI
  • Which DI container will satisfy this
  • Where should I do Injection with Ninject 2+ (and how do I arrange my Modules?)
  • Design - Where should objects be registered when using Windsor

Generic Interface dependency injection into factory

As suggested in the comments, you may try to specify ICreateOrders as

ICreateOrders<out TOrderRequest, out TOrderResponse>

You should then be able to write and to resolve successfully :

kernel.Bind(typeof(ICreateOrders<,>)).To(typeof(OrderCreator))


Related Topics



Leave a reply



Submit