50

I have decided to use IoC principles on a bigger project. However, i would like to get something straight that's been bothering me for a long time. The conclusion that i have come up with is that an IoC container is an architectural pattern, not a design pattern. In other words, no class should be aware of its presence and the container itself should be used at the application layer to stitch up all components. Essentially, it becomes an option, on top of a well designed object-oriented model. Having said that, how is it possible to access resolved types without sprinkling IoC containers all over the place (regardless of whether they are abstracted or not)? The only option i see here is to utilize abstract factories which use an IoC container to resolve concrete types. This should be easy enough to swap out for a set of standard factories. Is this a good approach? Has anyone on here used it and how well did it work for you? Is there anything else available?

Thanks!

alexandrul
  • 12,856
  • 13
  • 72
  • 99

2 Answers2

72

As you have already figured out, Dependency Injection (DI) itself is only a collection of patterns and techniques.

At the root of the application we wire up all necessary object graphs. This place is called the Composition Root, and we can use a DI Container to do this wiring for us, or we can do it manually (Pure DI).

The point is that there's only one place in your application where there's a strong reference to a particular piece of technology (your DI Container). The rest of the app is blissfully unaware of how the object graph was wired up - all that matters is that all required dependencies were correctly injected (and you can use Constructor Injection with Null Guards to guarantee that this is so).

The Abstract Factory pattern is a very useful pattern when it comes to DI. In essence, use Abstract Factory when:

  • You need to supply one or more parameters only known at run-time before you can resolve a dependency.
  • The lifetime of the dependency is conceptually shorter than the lifetime of the consumer.

Examples and more information is available here:

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • 1
    I think i'm almost there. Stay with me here :) Let's just say i have IFruit interface which is implemented by class Apple. After registering this concrete type, i want to use it in my button click event in a Windows Form. How would i get to class Apple without explicitly accessing IoC container from the button event? –  Jan 03 '10 at 18:29
  • 7
    That depends: are there many IFruit instances in your app, or only one? If there's only one, it should already be injected into the class with the button click handler. If there are many, you will most likely need an IFruitFactory that can create an IFruit instance from other run-time values. In the latter case, the IFruitFactory would be the injected dependency. – Mark Seemann Jan 03 '10 at 18:58
  • Considering only one IFruit instance exists, the only way i see it being injected into the Form class with the button click event is if i change the form constructor to include the IFruit interface and then register the Form itself with the IoC container to perform constructor injection. Does this sound correct? Thanks for helping out! –  Jan 03 '10 at 19:27
  • IoC containers (like CDI, Spring, Guice, etc) if You look carefully You will se that IoC looks exactly like abstract factory. Calling _**container.getBeanForType(BeanType.class)**_ we are performing creation process without any knowledge on how to create concrete object on given platform. The mentioned platform is defined by a set of all injectable beans (conditional beans, profiles, dynamicaly created beans in code that performs more complex conditions, etc) – rzur2004 Jun 24 '17 at 19:34
  • Should the factory concrete implementation have access to the ioc container interface in order to return the correct instance of the particular interface requested to the factory? – tonix Mar 30 '18 at 07:47
  • @tonix That's one among several options; see here for more: http://blog.ploeh.dk/2012/03/15/ImplementinganAbstractFactory – Mark Seemann Mar 30 '18 at 08:13
  • @MarkSeemann Thank you. I have read your article. What do you mean by `there's no longer a ready-to-use implementation packaged together with the LazyOrderShipper2 class.` and `there's no longer a ready-to-use implementation` in the second and third option? You mean, there will be only one type which implements `IOrderShipper` within the container and if you want to use another implementation you have to change the config of your container for that `IOrderShipper`? – tonix Mar 30 '18 at 12:43
  • @tonix If you have questions about the article, I think we should do other Stack Overflow users the favour of continuing the discussion over there. You're welcome to add a comment :) – Mark Seemann Mar 30 '18 at 12:48
4

Well at the top most part of your application you will need a Bootstrap class that loads the IOC context. This context then will provide the actually instantiated objects and therefore acts as a factory.

But this should only happen with very few objects and the user of your Bootstrap/Factory class should know as little about the underlying architecture as possible. For example if you configured a HTTP server object completely via IOC and you want to start it your Bootstrap class only needs to provide a getHttpServer() method. Then your programs main method only needs to call Bootstrap.getHttpServer().start() to get it running.

The wiring of your other objects has already been done by the application context e.g. you configure Object A via IOC which is part of Object B so you configure Object B with the reference to Object A. None of them usually need to know neither about the container nor the factory.

Daff
  • 43,734
  • 9
  • 106
  • 120