I have a factory class that creates a couple of different types of class. The factory is registered with the container. What is the recommended way of creating the classes inside the factory, given that they also have dependencies. I clearly want to avoid a dependency on the container but if I new those classes then they won't be using the container. e.g.
public class MyFactory
{
public IMyWorker CreateInstance(WorkerType workerType)
{
if (workerType == WorkerType.A)
return new WorkerA(dependency1, dependency2);
return new WorkerB(dependency1);
}
}
So the question is where do I get those dependencies from.
One option could be to make them dependencies of the factory. e.g.
public class MyFactory
{
private Dependency1 dependency1;
private Dependency2 dependency2;
public MyFactory(Dependency1 dependency1, Dependency2, dependency2)
{
this.dependency1 = dependency1; this.dependency2 = dependency2;
}
public IMyWorker CreateInstance(WorkerType workerType)
{
if (workerType == WorkerType.A)
return new WorkerA(dependency1, dependency2);
return new WorkerB(dependency1);
}
}
Another could be to register the worker types and make those dependencies of the factory e.g.
public class MyFactory
{
private IWorkerA workerA;
private IWorkerB workerB;
public MyFactory(IWorkerA workerA, IWorkerB, workerB)
{
this.workerA = workerA; this.workerB = workerB;
}
public IMyWorker CreateInstance(WorkerType workerType)
{
if (workerType == WorkerType.A)
return workerA;
return workerB;
}
}
With the first option I feel like I am leeching the dependencies of the workers into the factory. With the second option the workers are created when the factory is created.
Factory and Dependency injection both are the design pattern which can be used to enhance loose coupling abilities between the software components. Factory design pattern is used to create objects. But, injection and life cycle management of the object should be handled by programmer within the application.
Dependency Injection is more of a architectural pattern for loosely coupling software components. Factory pattern is just one way to separate the responsibility of creating objects of other classes to another entity. Factory pattern can be called as a tool to implement DI.
Dependency Injection (DI) is a design pattern used to implement IoC. It allows the creation of dependent objects outside of a class and provides those objects to a class through different ways. Using DI, we move the creation and binding of the dependent objects outside of the class that depends on them.
Simple Injector is thread-safe and its lock-free design allows it to scale linearly with the number of available processors and threads. You will find the speed of resolving an object graph comparable to hard-wired object instantiation.
I agree with @Phil, letting the factory take a dependency on the container is fine, but there's one peace of information missing in his answer.
You are probably trying to prevent taking a dependency on the container because you try to stay away from the Service Locator anti-pattern. I agree that Service Locator is an anti-pattern and should be prevented.
Whether or not a dependency on the container is an implementation of the Service Locator anti-pattern depends on where this consumer is defined. Mark Seemann explains this here:
A DI container encapsulated in a Composition Root is not a Service Locator - it's an infrastructure component.
So letting your factory depend on the container is fine as long as you define this MyFactory
implementation inside your composition root.
When you do this you'll soon get into trouble since a class that is defined in the composition root can't be referenced from the rest of the application. But that problem is easily solved by defining an IMyFactory
interface in the application and letting your factory implementation implement that interface (as you should do anyway to adhere to the Dependency Inversion Principle).
So your registration would become something like this:
container.RegisterSingleton<IMyFactory, MyFactory>();
And the implementation like this:
private sealed class MyFactory : IMyFactory
{
private readonly Container container;
public MyFactory(Container container)
{
this.container = container;
}
public IMyWorker CreateInstance(WorkerType workerType)
{
if (workerType == WorkerType.A)
return this.container.GetInstance<IWorkerA>();
return this.container.GetInstance<IWorkerB>();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With