0

I am trying to using IOC/DI container, but when come to creating a child window, what's the best practice?

Where I am having dilemma is :

public class ParentWindow : Form
{
    public void OpenChildWindow()
    {
        var child = IocContainer.Instance.Resolve<ChildWindow>(); // big issue !!! an-ti server locator pattern
        child.Show();
    }
}

Or

 public class ParentWindow : Form
    {

          private Container _container

          public ParentWindow(Container container) // no, no, you have dependence on container
          {
          }

        public void OpenChildWindow()
        {
            var child = _container.Resolve<ChildWindow>(); 
            child.Show();
        }
    }

My solution

public class ParentWindow : Form
{
    private IFormFactory _factory

    public ParentWindow(IFormFactory factory) // inject from IOC container
    {
    }

    public void OpenChildWindow()
    {
        var child = _factory.CreateChildWindow();
        child.Show();
    }
}

But with my solution, my factory kind of become my own IOC container, all my parent-ish window have to pass in a factory , isn't this make my factory become the new "server locator".

Is there any other better solution for this ?

LeY
  • 659
  • 7
  • 21

3 Answers3

2

The solution you suggest is a huge step in a right direction. The factory doesn't really smell like a locator, rather, it is a local factory, part of the domain it belongs to.

A step even further would be to forget the idea of family of factories (the interface) and have a concrete factory with pluggable implementation that internally uses a container (or doesn't use one) but offers a single api for its clients. This way you could remove the constructor injection of the factory into the form in favor of just using the factory's concrete type. The factory itself is configured in the Composition Root.

More details and code example in my blog entry

http://www.wiktorzychla.com/2016/01/di-factories-and-composition-root.html

Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106
0

Using DI implies that you consume the container as a Service Locator somewhere, preferably in one single line of code which executes exactly once. This is referred to as the "Composition Root", where the container is configured and the root of the object graph is created.

With this in mind- the topmost code in your example does not violate this principle.

SIDENOTE:

What I always do is wrap the Container framework code with my own class so that I can switch DI frameworks more easily- consider it.

Eyal Perry
  • 2,255
  • 18
  • 26
  • Using the DI doesn't imply consuming the container directly. It could be even considered a code smell to have the dependency explicit across the whole stack. Rather, with a combination of both the Composition Root and the Local Factory you can have only the top of the stack dependand of the container and use local factories everywhere with no dependency to any container at all. – Wiktor Zychla Sep 28 '16 at 18:48
  • I agree completely, and this is exactly what I said- if you read carefully- minus the local factories part which I didn't mention. (edited the answer so it would be clearer). @WiktorZychla – Eyal Perry Sep 28 '16 at 18:49
  • Note that the CR is only a half of the story. You can configure the container there but yet you somehow need to pass the container down the stack. The idea of local factories is the other half then, using local factories you eliminate the need to reference the container. – Wiktor Zychla Sep 28 '16 at 18:55
  • In WPF you can get rid of that necessity quite easily, by either rolling your own Markup Extension or using some MVVM Framework which usually takes care of such nuisances. I'm sure there are some frameworks lying around for WF as well. I think factories are in some way an embodiment of a service locator, as well as another issue - they imply control over instance lifecycle, which in the classic DI scenario should not be left up to the dependent class. @WiktorZychla – Eyal Perry Sep 28 '16 at 19:02
0

First example: I don't like because you also has dependency which you cannot Unit test. It will resolve instance of ChildWindow and you cannot control (mock) it.

Second example: I don't like because you are using class Container not interface.

Third example: It will works better than previous and sometimes I use factory on that way. It it can be fully unit tested.

Usually I think that is better to use DI container as factory because it provides more functionalities such as e.g. object lifetime...

I never used class ChildWindow but if I cannot define in constructor interface i will rather implement some ChildWindowWrapper : IChildWindowWrapper and use that wrapper. It will simplefy unit testing and it can be used from DI container.

kat1330
  • 5,134
  • 7
  • 38
  • 61
  • can you provide some examples of "use DI container as factory" and "ChildWindowWrapper" – LeY Sep 28 '16 at 19:28
  • @LeY Sorry if sound equivocally. I want to say that I will rather use DI container for creations of new instances of objects instead of using Factory pattern (method). In example, if class doesn't implement Interface or Abstract class I will use wrapper class. Wrapper is class which encapsulate certain functionalities which you need. Instead using directly in code your class you will need to use Wrapper directly. Wrapper will needs to implement interface and you will be able to register with your DI container. – kat1330 Sep 28 '16 at 20:23