Dependency Injection: How to configure interface bindings for wrapping
So, let's say I have an interface IThingFactory
:
public interface IThingFactory
{
Thing GetThing(int thingId);
}
Now, let's say I have a concrete implementation that retrieves Thing
s from a database. Now, let's also say I have a concrete implementation that wraps an existing IThingFactory
and checks for a Thing
's presence in, say, an in-memory cache before hitting the wrapped IThingFactory
. Something like:
public class CachedThingFactory : IThingFactory
{
private IThingFactory _wrapped;
private Dictionary<int, Thing> _cachedThings;
public CachedThingFactory(IThingFactory wrapped)
{
this._wrapped = wrapped;
_cachedThings = new Dictionary<int,Thing>();
}
public Thing GetThing(int thingId)
{
Thing x;
if(_cachedThings.TryGetValue(thingId, out x))
return x开发者_StackOverflow社区;
x = _wrapped.GetThing(thingId);
_cachedThings[thingId] = x;
return x;
}
}
How would I deal with a scenario like this using dependency injection with something like, say, Ninject, so that I could configure the DI container so that I can inject or remove a caching proxy like this, or, say, something that does logging, or (insert here)?
You can do something along the lines of:
Bind<IThingFactory> ().To<DefaultThingFactory> ().WhenInjectedInto<CachedThingFactory> ();
Bind<IThingFactory> ().To<CachedThingFactory> ();
This will let consumers not need to specify a name attribute, and is still relatively easy to further enhance. If you later wanted to add an additional "decorator" layer for logging, you could do:
Bind<IThingFactory> ().To<DefaultThingFactory> ().WhenInjectedInto<LoggingThingFactory> ();
Bind<IThingFactory> ().To<LoggingThingFactory> ().WhenInjectedInto<CachedThingFactory> ();
Bind<IThingFactory> ().To<CachedThingFactory> ();
Not the prettiest, but it works.
One of the benefits of DI framework is that you don't have to do things like these. Ninject has various scopes that you can use to specify the lifetime of your objects. It'll handle caching and stuff for you.
Read more here: http://kohari.org/2009/03/06/cache-and-collect-lifecycle-management-in-ninject-20/
I suppose you are searching for named binding, documented here:
https://github.com/ninject/ninject/wiki/Contextual-Binding
Bind<IThingFactory>().To<CachedThingFactory>().Named("TheCachedThing");
Bind<IThingFactory>().To<DefaultThingFactory >().Named("ThePureThing");
and then
public CachedThingFactory([Named("ThePureThing")] IThingFactory wrapped)
{
this._wrapped = wrapped;
_cachedThings = new Dictionary<int,Thing>();
}
and for the consumer of the CachedThingFactory
public ThingFactoryConsumer([Named("TheCachedThing")] IThingFactory thingFactory)
{
_thingFactory = thingFactory;
}
精彩评论