Lawrence Wagerfield
Lawrence Wagerfield

Reputation: 6611

Dependency Injection - What If Dependency Lifetimes Are Shorter Than The Dependent Object?

I realise that DI is a very flexible design pattern, although I'm struggling to accept it as my 'silver bullet' for creating decoupled code.

Here's why: What happens when the dependent object has a longer lifetime than the dependencies it has been injected with?

Example application: I have a BusinessLogic class which is instantiated for the lifetime of my application. This class requires a DataContext object to perform database operations. I have thefore created an abstract DataContextFactory with two implementations: StaticDataContextFactory and WebDataContextFactory. The former maintains a single DataContext for the lifetime of the application, whereas the latter will create new DataContexts for each HTTP request.

Problem in the example : As you can see, all will be fine when the StaticDataContextFactory is used. However, when the WebDataContextFactory is used the BusinessLogic will fail, since it's injected with a DataContext which will expire/dispose once the first request completes.

My question is: Must all dependent objects have a lifetime which is less or equal to the lifetime of its dependencies? If so, then what happens when the lifetime of each dependency is unknown to the code which instantiates the dependent classes?

Upvotes: 3

Views: 2208

Answers (4)

Nicholas Blumhardt
Nicholas Blumhardt

Reputation: 31857

As other posters have pointed out, there are proxy-based solutions to this. I'd put that in the 'last resort' category though.

You can refactor to remove this inconsistency, and I think the end result will be nicer to work with in the long run. I don't know a lot about your scenario, but a few things you could consider:

  1. Get rid of the factories, let the container inject the DataContext and then use the container's lifetime control to adjust the lifetime of the DataContext in different environments

  2. Don't make the BusinessLogic component single-instance. If you create a new one for each use, it will naturally pick up a web-scoped DataContext if DC is configured that way, or the single DC in the other configuration

  3. If BusinessLogic has state or is expensive to instantiate, move the expensive/stateful parts into sub-components that have single-instance lifetime

I've seen the proxy-based solution that can be used in Spring - it is personal taste but I'd be wary about how understandable this solution will be long-term. You'd have to be very disciplined to make sure that anything returned from the 'current web request' through the proxy would not be referenced or kept around longer than the request that owns it...

Working successfully with lifetime in IoC really relies heavily on keeping a clean separation between units of work, which in a web environment is pleasant and natural - it will pay to go with the flow if you can.

Hope this helps, Nick

Upvotes: 1

Ladlestein
Ladlestein

Reputation: 6150

The Spring framework's web integration addresses this problem using proxies and aspects. Longer-scoped objects are injected with proxies to the shorter-scoped objects. Each proxy knows how to fetch the "current" version of its shorter-scoped delegate, via the HTTP session or HTTP request (for session- and request-scoped beans, respectively).

See http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes-other-injection

Upvotes: 1

Pedro
Pedro

Reputation: 382

Why can't you ask the XXXDataContextFactory for the "Current" DataContext? Your Static factory will always return the same one, while your Web factory will return one based on the current HttpRequest.

Upvotes: 0

bleepzter
bleepzter

Reputation: 10015

I have been pondering a similar question. (Check my post on DI: Dependency Injection Container, Second Answer) I realized that a proper implementation using Interface Injection would actually do the trick.

The reason I think it may work well is because while it is common to extract an interface from an object, as long as the interface hierarchies are properly designed, even if the objects go out of scope, the data relevant to the interface will actually persist. Therefore you would not end up having a dependency that goes out of scope before your actual object has been released by the code that consumes it.

In the example I've shown I rolled out my own "DI" although it is not really a true DI pattern, i believe it does the job pretty well.

Upvotes: 0

Related Questions