Search code examples
ioc-containerencapsulation

Should I encapsulate my IoC container?


I'm trying to decide whether or not it makes sense to go through the extra effort to encapsulate my IoC container. Experience tells me that I should put a layer of encapsulation between my apps and any third-party component. I just don't know if this is bordering on overkill.

I can think of situations where I might want to switch containers. For instance, my current container ceases to be maintained, or a different container is proven to be more light-weight/performant and better fits my needs. If this happens, then I'll potentially have a lot of re-wiring to do.

To be clear, I'm considering encapsulation of the registration and resolution of types. I think it's a no-brainer to encapsulate resolution - I'd hope it's common practice to have a helper/util class delegating to the container.

EDIT:

The assumption is that I prefer to wire-up my types programmatically for type-safety, compile-time checking and refactorability. It's this code and its dependency on the container that I'm looking to protect myself from.

I've also been using an IoC container for several other projects that share a lot of the same relationships, but the container is a pain to work with so I want change. But, a change means I lose the reusability of the registration code. Hence, why I'm contemplating encapsulation. It's not a huge burden, but one that I'd, nevertheless, like to mitigate.

I'm looking to:

  • Minimize the impact of change in containers / versions of containers
  • Provide some level of type-registration consistency across projects that may use different containers
  • Provide interface methods that make sense to me (RegisterSingleton<T,T> rather than RegisterType<T,T>( SomeLifetimeProvider ) - using Unity as an example).
  • Augment the container as conditions/scalability requirements change e.g. adding better caching, logging, etc during resolution/registration.
  • Provide my own model for registering type mappings.
    • Say I want to create a bunch of RegistrationHandler objects in an assembly/package and so I can easily segregate registration responsibilities across multiple classes and automatically pickup these handlers without changing code anywhere else.

I realize this is a bit subjective, so pros/cons might be helpful

Thanks!


Solution

  • Do it later, and only if you actually have the need to change IOC containers.

    Pick an IOC container that is non-invasive. That is, one where the objects being connected to each other don't have any dependencies on the IOC container. In this case, there's nothing to encapsulate.

    If you have to pick an IOC container that requires that you have dependencies on the container, choose one with the simplest dependencies/API you can. If you need to replace this IOC container (and you probably won't), implement adapters that bridge the new API to the old one.

    In other words, let the first IOC container be the one that defines the interfaces for any future container so that you don't have to invent your own, and you can delay any of this sort of work until you absolutely need it.

    EDIT:

    I don't see a way of guaranteeing type-safety short of either:

    1. Designing a relatively complex implementation of the Builder pattern along with visitor implementations that would write IOC configuration files, or something equivalent.
    2. Implementing a type-safe IOC configuration DSL. (My choice if I had multiple apps that required swappable IOC containers.)