Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Injection for objects that require parameters

All of our reports are created from object graphs that are translated from our domain objects. To enable this, we have a Translator class for each report, and have been using Dependency Injection for passing in dependencies.

This worked great, and would yield nice classes structured like this:

public class CheckTranslator : ICheckTranslator
{
   public CheckTranslator (IEmployeeService empSvc
                         , IPaycheckService paySvc)
   {
      _empSvc = empSvc;
      _paySvc = paySvc;
   }

   public Check CreateCheck()
   {
      //do the translation...
   }
}

However, in some cases the mapping has many different grouping options. As a result, the c-tor would turn into a mix of class dependencies and parameters.

public class CheckTranslator : ICheckTranslator
{
   public CheckTranslator (IEmployeeService empSvc
                         , IPaycheckService paySvc
                         , bool doTranslateStubData
                         , bool doAttachLogo)
   {
      _empSvc = empSvc;
      _paySvc = paySvc;
      _doTranslateStubData = doTranslateStubData;
      _doAttachLogo = doAttachLogo;
   }

   public Check CreateCheck()
   {
      //do the translation...
   }
}  

Now, we can still test it, but it no longer really works with an IoC container, at least in a clean fashion. Plus, we can no longer call the CreateCheck twice if the settings are different for each check.

While I recognize it's a problem, I don't necessarily see the right solution. It seems kind of strange to create a Factory for each class ... or is this the best way?

like image 695
Andrew Avatar asked Apr 03 '10 23:04

Andrew


1 Answers

Shot in the dark here, but could you move those parameters to the method instead?

In other words:

public Check CreateCheck(bool doTranslateStubData, bool doAttachLogo)
{
   //do the translation...
}

Do those parameters have to be passed in via the constructor?

(Note - if your response to this is "there are too many methods for that to be practical", then part of the problem may be that the abstraction is too coarse).


Another option (it's really hard to say without understanding the domain model and injection patterns) would be to introduce a parameter object that is itself managed by the injector:

public interface ICheckConfiguration
{
    bool AttachLogo { get; }
    bool TranslateStubData { get; }
}

Then inject this with the constructor:

public CheckTranslator (IEmployeeService empSvc, IPaycheckService paySvc,
    ICheckConfiguration config)
{
    // etc.
}   

This should be enough. You can then create a concrete CheckConfiguration class that takes those two bool properties in its constructor, and configure your container to create different instances of the parameter object (interface) based on a higher-level DI parameter.


The last thing I think I should mention is that just because you're using DI doesn't mean that everything has to be managed by the container. It's not such a bad thing to create CheckTranslator objects in an ad-hoc fashion if there's only one kind of "translator". As long as the translator still depends on abstractions, which it does here, then maybe you shouldn't be injecting it at all, just let higher-level DI-enabled classes create them ad-hoc.

like image 183
Aaronaught Avatar answered Sep 27 '22 19:09

Aaronaught