views:

97

answers:

1

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?

+7  A: 

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.

Aaronaught
I'm too tired to edit my answer again right now but there is one more possibility, which is to use the Abstract Factory Pattern and inject an `[I]CheckTranslatorFactory`. That would be a valid way of creating `CheckTranslator` or `ICheckTranslator` objects of an unknown concrete type, with parameters; instead of injecting the actual translator instance, you inject the factory, and have different factories responsible for creating different translator subtypes. Only really necessary/useful if you intend to use polymorphism for the `CheckTranslator`.
Aaronaught
Use ICheckConfiguration is a good idea. Pass in a Null pattern implementation for the default case, and pass in a real implementation for other cases.
Lex Li
Makes sense. Thanks!
Andrew