47

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?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Laila
  • 499
  • 1
  • 5
  • 7

2 Answers2

74

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.

Patryk
  • 22,602
  • 44
  • 128
  • 244
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • Why do you create Foo manually? In that case FooFactory has unnecessary dependencies. Why don't you use container.Resolve(dc) instead of new Foo(this.serializer, this.fileHandler, dc)? – Yauheni Sivukha Jul 15 '10 at 12:03
  • 13
    Because that would be the Service Locator anti-pattern (http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx). The DI Container must not invade the rest of the application. However, some containers (e.g. Windsor) can automatically implement and emit implementations of Abstract Factories, in which case FooFactory would be completely redundant. If you want to use the DI Container, go all the way :) – Mark Seemann Jul 15 '10 at 12:28
  • 1
    I agree that Service Locator is anti-pattern, but every rule has exceptions. You should not follow this rule blindly! You wire your objects manually, your abstract factory has incorrect dependencies. This a smell of bad design, is not it? DI container is intended to get rid of this smells, is not it? So use DI container to create Foo! You right :) If you want to use the DI Container, go all the way :) – Yauheni Sivukha Jul 15 '10 at 12:51
  • 7
    Dynamic factories á la Windsor aside, why would FooFactory have incorrect dependencies? It still uses Constructor Injection, so you still need the DI Container to wire it up for you. The point is that you can't create Foo without DomainClass, which is only available at run-time. Using the DI Container as a Service Locator is not going to change that, but would add a tight coupling to the DI Container, as well as a logical coupling to Foo. This would only leave you worse off than the above implementation. – Mark Seemann Jul 15 '10 at 13:01
  • 2
    Can an abstract factory return a concrete type ? Foo here is a concrete type as you can new it. I thought abstract factory were meant to return only abstractions ? Or am I wrong ? – darkey Apr 28 '13 at 01:35
  • As an aside, would not a generic interface satisfy this globally? And it would become blindlying apparent what is needed. Plus it could over contravariance/covariance. eg. public interface IFactory { TCreate Create(); } To add parameters to the inteface: public interface IFactory { TCreate Create(TParameter parameter); } – DaFlame Jan 31 '14 at 16:55
  • @DaFlame A generic factory wouldn't know the details of how to instantiate each class. For example, Foo depends on DomainClass. – drifter Feb 09 '14 at 17:05
  • @MarkSeemann I very much like your line of reasoning on everything :) However, I do have a question, perhaps naive but I've been reading allot of conversation about newables and injectables. The trending thought is that injectables should only take other injectables into the constructor. Is this just meant as a general rule to keep DI simple, so you don't need factories? To me it seems very impractical, as there are so many cases where I find I need an abstract factory, which typically injects them together... – GetFuzzy Jul 18 '14 at 01:54
  • 1
    @GetFuzzy An Abstract Factory is also a 'newable', but perhaps this helps: http://blog.ploeh.dk/2011/03/03/InjectionConstructorsshouldbesimple See also chapter 6 of [my book](http://amzn.to/12p90MG). And here's another take on selecting dependencies based on run-time values: http://stackoverflow.com/a/22705794/126014 – Mark Seemann Jul 18 '14 at 06:11
  • @GetFuzzy Really sorry but [you triggered my alot synapse](http://hyperboleandahalf.blogspot.ie/2010/04/alot-is-better-than-you-at-everything.html) :P – Ruben Bartelink Jul 18 '14 at 10:21
  • @MarkSeeman : Thanks for the advice on using AbstractFactories to create classes which need values available only at runtime. The problem I'm facing is that I need to apply a cross cutting concern to that class, and I can't think of a way to do it without having my AbstractFactory depend on the IOC container. Is there a better way to solve this issue? – Arnab Chakraborty Aug 07 '14 at 07:37
  • @MarkSeemann Here is a link to my original question: https://stackoverflow.com/questions/25176984/how-to-correctly-apply-a-cross-cutting-concern-to-a-class-created-by-an-abstract – Arnab Chakraborty Aug 07 '14 at 07:51
  • @MarkSeemann, as always, a pleasure to read. I have come to find it useful in several cases to implement my factories in a different way. If I have N possible implementations that the factory can return, I have them injected in the constructor and instead of a "Create" method to a "Get" method. The disadvantage of this is that more instances are created than needed. The advantage is service location is not used, yet we still get the benefits of having the IoC manage the lifetime of the dependencies. – Fabio Milheiro May 20 '16 at 08:44
  • @MarkSeemann, also this approach is particularly useful in some cases I am working where I use my "factory" several times during the same HTTP request. Newing it up will just create new instances. Unless I cache the factory results in a private field. That could also work... – Fabio Milheiro May 20 '16 at 08:45
  • 1
    @Bomboca If I understand you correctly, you're describing one of these alternative: http://blog.ploeh.dk/2013/01/11/PartialTypeNameRoleHint http://blog.ploeh.dk/2013/01/10/RoleInterfaceRoleHint http://blog.ploeh.dk/2013/01/09/MetadataRoleHint If so, I completely agree. – Mark Seemann May 20 '16 at 10:13
  • @MarkSeemann Exactly! And I thought I was being original. I don't feel original any more but validated instead :) thanks! – Fabio Milheiro May 20 '16 at 10:17
  • Lol, can't believe no one noticed the blatant breach of IoC at the `return new Foo(this.serializer, this.fileHandler, dc)` statement. So Mark, your solution to maintain constructor injection is to create a Factory that breaks it? – Ash Mar 09 '18 at 03:06
  • @Ash How is anything broken? Perhaps this helps http://blog.ploeh.dk/2014/12/24/placement-of-abstract-factories – Mark Seemann Mar 09 '18 at 05:57
  • @Mark Because your factory isn't accepting a `Foo` object, but creating it. Yes, I get that that's the point of the `Create` method (obviously), but my point is due to the `Create` method, your factory breaks IoC - it's internally instantiating rather than accepting via constructor injection. – Ash Mar 09 '18 at 06:33
  • @Ash Does this help, then? http://blog.ploeh.dk/2012/03/15/ImplementinganAbstractFactory – Mark Seemann Mar 09 '18 at 06:50
  • @Mark Reading through that, the two alternatives you suggest are using Service Locator and Dynamic proxy, is that correct? – Ash Mar 09 '18 at 07:03
  • @Ash I very explicitly don't suggest using a Service Locator; it's right there in the article. That said, I prefer the [Pure DI](http://blog.ploeh.dk/2014/06/10/pure-di) variation shown here. – Mark Seemann Mar 09 '18 at 07:14
  • @Mark So you are suggesting going with Pure DI instead of a factory? – Ash Mar 09 '18 at 07:26
  • @Mark Sorry but I'd rather not go through an entire blog or book just to get to the punchline. if you could edit your answer to reflect on my comments that would be better. – Ash Mar 09 '18 at 07:28
  • @Ash No, I definitely suggest using Pure DI [unless you have very specific reasons to use a DI Container](http://blog.ploeh.dk/2012/11/06/WhentouseaDIContainer). The use of a factory is completely unrelated to that. – Mark Seemann Mar 09 '18 at 07:29
  • @Mark But my original comment was nothing to do with whether to use pure DI or a container. It was about your factory breaching the most fundamental principle of IoC. – Ash Mar 09 '18 at 07:31
  • @Ash Why? Because it uses the `new` keyword? – Mark Seemann Mar 09 '18 at 07:32
  • @Mark because it instantiates internally rather than accept as an injection in its constructor....like I've already mentioned. – Ash Mar 09 '18 at 07:34
  • @Ash So, when using DI, no object is allowed to instantiate any other object internally? – Mark Seemann Mar 09 '18 at 07:36
  • @Mark Correct. Not unless the instantiating object is the Composite Root (System and primitive types are exempted). – Ash Mar 09 '18 at 07:38
  • @Ash *"Not unless the instantiating object is the Composite Root"*. Indeed, and that's where you should put the above factory class. – Mark Seemann Mar 09 '18 at 07:42
  • @Mark that puts a restriction on where you must put your factory classes. A terrible restriction. – Ash Mar 09 '18 at 07:43
  • @Mark The only thing a well designed Composite Root would do is Register/Resolve. And that's it. – Ash Mar 09 '18 at 07:44
1

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.

Metro
  • 1,464
  • 14
  • 24
  • there is a post that agrees with this point of view (mark^ wrote it) but then every consumer would need to implement their own factory implementation. (just an add on not a good or bad to your post) [http://blog.ploeh.dk/2012/03/15/ImplementinganAbstractFactory/] – workabyte Nov 21 '14 at 22:21
  • @Metro Correct me if I'm not reading your proposal correctly. So your proposal is to have the factory resolve the abstract type using the container? So essentially Service Locator? But a Service Locator call that doesn't hurt your soul as much since implementation of the factory is at the same level as the IoC container? – Ash Mar 09 '18 at 03:03