6

I recently asked about doing DI properly, and got some links to blog posts about it. I think I have a better understanding now - separate object construction from logic, by putting it in factories. But all of the examples are for things like websites, and say to do all the wiring at startup. Call one large factory which news everything and passes in all the dependencies.

But what if I don't want to instantiate everything up front? I have an object which contains a list of other objects which it can delegate to, but they are expensive, and used one at a time, so I construct them when needed and let them get collected when I'm done. I don't want to put new B() inside the logic of A because I would rather use DI - but how? Can A call the factory? That doesn't seem much better, unless the factory is maintaining state including the current dependencies. I just don't want to pass the full list of Bs into A when it's constructed, since it would be wasteful. If you want, B doesn't necessarily have to be inside A, although it makes logical sense (A is a game level, B is a single screen), but in any case the logic of A dictates when B is created.

So, who calls the factory to get B, and when?

Clarification: I'm not using framework for DI. I wonder if the term DI implies that?

Tesserex
  • 17,166
  • 5
  • 66
  • 106
  • Great question. I've been confounded by this problem too. Also, sometimes I want multiple instantiations of something (and an arbitrary number of them at that!) and have been very confused how that is supposed to work. With Ninject I've just sucked it up and injected `IKernel` but I'm given to understand that is frowned upon. (though in my experience, very powerful and have yet to regret it -- and no, I am not even remotely interested in "swapping out" my DI framework, so that benefit is moot to me) – Kirk Woll Oct 21 '11 at 22:50
  • Its only frowned upon by developers that have some religous understanding of patterns. While I wouldn't go hog wild where every type knows about IKernel, or whatever its called in your flavor of DI framework, sometimes that is the best way to go. I've done this as well, and nothing has exploded on me. – Andy Oct 22 '11 at 00:56

2 Answers2

6

In Ninject, you can register Func<B> and request that in the constructor to A.

Autofac will automagically supply Func<B> if B is already registered.

Or, you can take the more straight forward approach and define an explicit factory for B, and request that factory in the constructor; its just more typing as you'd have to create a factory for every dependency you want to lazily initialize.


Here's another SO answer that shows Ninject style factory methods: How do I handle classes with static methods with Ninject?


@Not Using A Framework: If you can, I'd probably look into using one: a IoC/DI framework usually will handle delayed creation for you out of the box.

If you want to continue to roll your own, then just pass the factory that creates B to your A object. Or, if you just don't like raw Funcs and don't want to have to create explicit factories for all your objects, then you could look into using Lazy<B> for a more formalized solution.

Community
  • 1
  • 1
David Faivre
  • 2,302
  • 3
  • 23
  • 25
  • The solution I went with doesn't exactly match any of these answers (I went with instantiating most things up front), but this one gave me some new insights into the approaches of DI, so I'm accepting it. – Tesserex Oct 23 '11 at 21:53
1

There are typically two patterns for using rarely needed objects that are expensive to create. The first pattern is using a factory, as David Faivre suggests. The other is by using a proxy.

A proxy is -from a design perspective- probably the cleanest solution, although it might need more code to implement. It is the cleanest, because the application can be totally unaware of this, because you don't need an extra interface (as the factory approach needs).

Here is an simple example with some interface and an expensive implementation:

interface IAmAService
{
    void DoSomething();
}

class ExpensiveImpl : IAmAService
{
    private object x = [some expensive init];

    void IAmAService.DoSomething() { }
}

No you can implement a proxy based on that interface, that can delay the creation of that implementation:

class ServiceProxy : IAmAService
{
    private readonly Func<IAmAService> factory;
    private IAmAService instance;

    public ServiceProxy(Func<IAmAService> factory)
    {
        this.factory = factory;
    }

    void IAmAService.DoSomething()
    {
        this.GetInstance().DoSomething();
    }

    private IAmAService GetInstance()
    {
        // TODO: Implement double-checked lock only a single
        // instance may exist per ServiceProxy.
        if (this.instance == null)
        {
            this.instance = this.factory();
        }

        return this.instance;
    }
}

This proxy class accepts a factory delegate as dependency, just as David Faivre described in his answer, but this way the application won't have to depend on the Func<IAmAService>, but can simply depend on IAmAService.

Now instead of injecting an ExpensiveImpl, you can inject a ServiceProxy into other instances:

// Create the proxy
IAmAService service =
    new ServiceProxy(() => new ExpensiveImpl());

// Inject it into whatever you wish, such as:
var customerService = new CustomerService(service);
Steven
  • 166,672
  • 24
  • 332
  • 435
  • 1
    +1 -- It always bugged me that to create a "factory" I had to create two interfaces: one for IService and one for IServiceFactory, and then implementations for both (this is why I end up just using Func -- and because I'm lazy, will probably continue to do so). However, I like the fact that you're hiding the factory in a direct implementation of IService. Still two implementations, but now at least its just one interface. Neeto. – David Faivre Oct 22 '11 at 13:54