Is it a bad design to specify default bindings when using Inversion of Control (IOC) containers and dependency injection (DI)?

softwareengineering.stackexchange https://softwareengineering.stackexchange.com/questions/195020

Question

I'm using Ninject, but this is not a Ninject-specific question. I'm wondering if the advanced and flexible capabilities of the IoC container are giving me enough rope to hang myself with a bad application design.

I've got a service interface:

public interface IBuilderService {
    IBuilder Create(string category, string clientID);
}

and I lean on Ninject Factory Extension's ToFactory() to create what I'd guess you'd call a proxy implementation at runtime.

I have IBuilder bindings like this:

kernel.Bind<IBuilder>().To<NullObjectBuilder>(); // for unbound categories
kernel.Bind<IBuilder>().To<CatOneBuilder>();
kernel.Bind<IBuilder>().To<CatTwoBuilder>();
kernel.Bind<IBuilder>().To<CatThreeBuilder>();
kernel.Bind<IBuilder>().To<CatOneBuilder_ClientA>();
kernel.Bind<IBuilder>().To<CatOneBuilder_DefaultClient>(); // for unbound clients
// etc...

I've been experimenting with custom instance providers and binding generators with Ninject (I'm guessing other IoC containers may have similar constructs for overriding basic binding behavior), but I have two distinct binding scenario goals:

  1. if a category of binding cannot be resolved from the IBuilderService.Create category argument, then a NullObjectBuilder should be resolved - this is the default binding in this case.
  2. if a clientID of a binding cannot be resolved, then a default client implementation like CatOneBuilder_DefaultClient for a category of CatOne should be resolved - this is the default binding in this case.

This is a situation where unknown category requests are expected, so it seems a shame to use expensive exception handling for something I know will happen very often. I want there to be fallback behavior to "handle the unhandled" in a very plain way - in this case, it would be the NullObjectBulder for unknown categories, and *_DefaultClient for unknown clients of known categories - two distinct fallback behaviors for two different types of unknown behavior.

I'm having trouble keeping the two fallback behaviors mapped to their respective scenarios, but it's given me pause to think about the friction I'm feeling in fleshing out this design…

Is it a flawed design to have default bindings and the logic used to determine when one is needed contained in IoC custom implementations, rather than an exception being thrown? Is this a mis-use of IoC containers?

No correct solution

Licensed under: CC-BY-SA with attribution
scroll top