Just assume I have some class Foo, that has two dependencies: an ISerializer<T>
and an IFileAccessHandler
.
Now this class also has other dependencies, functional dependencies. I don't want anyone instantiating this class in an invalid state, so I'd also need to pass a domain object in the constructor.
But how can I have that handled by IoC when I also know what domain object to pass in the moment I'm actually creating class Foo?
I made the domain object a property that I have set by a Factory. So the Factory makes a Service Locator call to get a properly instantiated "Foo" class with it's dependencies, and further fills it up with the correct domain object and returns it.
But is this the best way to go? I would have preferred having the domain object part of my constructor to make it apparant you actually need to work with "Foo".
Any ideas? Am I missing something here?
The default solution to DI when you can't wire up a concrete type at registration time is to use an Abstract Factory
In your case, I would define an IFooFactory interface:
public interface IFooFactory { Foo Create(DomainClass dc); }
This will allow you to define a concrete implementation that knows about your infrastructure services.
public class FooFactory : IFooFactory { private readonly ISerializer serializer; private readonly IFileAccessHandler fileHandler; public FooFactory(ISerializer serializer, IFileAccessHandler fileHandler) { if(serializer == null) { throw new ArgumentNullException("serializer"); } if(fileHandler == null) { throw new ArgumentNullException("fileHandler"); } this.serializer = serializer; this.fileHandler = fileHandler; } public Foo Create(DomainClass dc) { return new Foo(this.serializer, this.fileHandler, dc); } }
In this way you can protect the invariants of your Foo class, enabling you to stay with Constructor Injection.
In the DI container, you can register the IFooFactory and corresponding implementation. Everywhere you have a DomainClass instance and need a Foo instance, you would then take a dependency on IFooFactory and use that.
I am also struggling with this issue. Mark's example is constrained in that the FooFactory is creating a concrete class Foo. What if it was to create an IFoo where the implementation is determined during startup configuration? This would imply for every alternative implementation of IFoo (FooA, FooB, etc) you would need a concrete implementation of the corresponding factory (FooAFactory, FooBFactory, etc). This strikes me as redundant.
If the factory is defined at the same level as the implementation and initialization of the Container, I do not see the weakness of referencing the container by the factory. It still keeps references of the container from leaking into the rest of your application.
Best regards,
Metro.
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