IoC with static and dynamic dependencies

I am trying to implement IoC in my application. I have this model:

interface IService; interface IComponent; class Service : IService Service() class Component : IComponent Component(IService service, object runtimeValue) { } 

At some point in my application, I need to get an IComponent . My application uses the IoC (Unity) container. I can register Service with a container, but I cannot do the same for Component b / c of its runtimeValue dependency. Accordingly , I should use the factory and indicate that wherever I need to get IComponent :

 interface IComponentFactory IComponent CreateComponent(object runtimeValue) class ComponentProvider : IComponentProvider ComponentProvider(IComponentFactory factory) { } IComponent CreateAndCacheComponent(object runtimeValue) { _component = factory.CreateComponent(runtimeValue) return _component } // other methods 

I should be able to register a factory with a container, so it should only have static dependencies. At the same time, it should be able to provide an instance of a service of the IService type needed to create the component.
Here is a factory implementation. The only thing I could think of was to use the Func<> delegate as a dependency:

 class ComponentFactory : IComponentFactory ComponentFactory(Func<IService> serviceFactoryDelegate) IComponent CreateComponent(object runtimeValue) { return new Component(serviceFactoryDelegate.Invoke(), runtimeValue) } 

... and register the delegate with the container as a static factory so that it returns the container to allow the service (I use Unity 1.2 on .net 2.0):

 Container .Configure<IStaticFactoryConfiguration>() .RegisterFactory<Func<IService>>(container => (Func<IService>)container.Resolve<IService>) 

Now I can use the container to resolve the ComponentProvider and get the component based on the runtime value:

 // this happens inside CompositionRoot provider = Container.Resovle<IComponentProvider>() component = provider.CreateAndCacheComponent("the component") 

Now I have some questions about this:

  • I am not happy that the factory calls new Component(...) . Isn't that a poor man?

  • Is the Hollywood principle preserved when using the Func<IService> in the factory constructor? I mean, it ends up calling the container. Recovers <> ... kind of like SL. The only difference is that the code is in the registration part of the application container, and not inside the factory class.

  • Is there anything (different) in this implementation as far as DI and IoC are concerned?

+4
source share
3 answers
  • No, it is not. The whole purpose of a factory is to instantiate a particular class.
  • In principle, yes, but, as I already asked in my comment, I do not understand why this is necessary. You can directly enter an instance of IService
  • This is a little harder than necessary. Why double redirect IComponentProvider IComponentFactory ? It seems that IComponentFactory does not add any benefit.

    Contribute ComponentProvider as follows:

     class ComponentProvider : IComponentProvider { ComponentProvider(IService service) { _service = service; } IComponent CreateAndCacheComponent(object runtimeValue) { _component = new Component(_service, runtimeValue); return _component; } 

    This will give you the following benefits:

    • You get rid of the unnecessary IComponentFactory interface along with the corresponding implementation.
    • No need to register factory for IService

Generally speaking, how you implement this depends on what you really need:

"runtimeValue" may be the same at runtime, for example. connection string, which is read from the settings. In this case, you do not need a factory / provider, you can just update the instance and register it in the container. Everyone who needs IComponent requests one in the constructor instead of the provider.

You only implement the factory and pass it as a dependency around if the "runtimeValue" really changes between calls to CreateAndCacheComponent .

+1
source
  • This is a big step from Poor Man DI, but it would be nice if you didn't have to change this factory method every time a new dependency is added to the Component constructor.
  • This is not a problem in itself. Think of it as if you were introducing an anonymous factory class. It can still be ridiculed for unit testing, and the bindings can be changed, so you still get the benefits of DI. But this is an added layer of abstraction, which is probably not needed. You can still avoid this in this case by entering the IService directly in the factory and not in Func .
  • Typically, when using dependency injection, you want to enter services, not values. The fact that you discover that you must have both may indicate that you need to revise your class API. For example, perhaps you should pass the value to the methods of the class, not the constructor. It is hard to say what the best approach would be without knowing the details.
+1
source

To question 1: there is nothing wrong with calling new in a factory. You have isolated an instance of one place in your application; you just made this place instead of factory instead of container.

If you ever needed to ridicule or change implementations, you are simply mocking or changing the factory implementation, not just the Component.

0
source

All Articles