1

Consider the case where we might want to make use of a service, such as

class MyService {
    public double calculateSomethingVeryComplex();
}

These kind of functional-looking classes (that contain only a single method) tend to show up only a single public method, although we know (or imagine, a least), they are composed by a lot of smaller methods internally:

class MyService {
    public double calculateSomethingVeryComplex()
    private double getA();
    private double getB();
    private double getC();
    ...
}

and, although the main method could usually pass its objects to getA(), getB(), ..., through method arguments, we generally tend to define them as class attributes (fields), to get the job done:

class MyService {
    private double val1;
    private double val2;
    private double val3;

    public double calculateSomethingVeryComplex()
    private double getA();
    private double getB();
    private double getC();
    ...
}

If not using dependency-injection, each time we need something very complex to be calculated, we simply instantiate a new MyService, call its only method, and we're done.

When using dependency-injection we have the apparent problem of wanting to instantiate MyService in the Composition Root, which is almost okay, although things can get messy with those private fields (for instance, in a multi-threaded scenario).

I see 3 main options here:

  1. Create a MyServiceFactory that I have as dependency to any class that wishes to use MyService. I don't like this approach as it may in certain kind of applications to skyrocket the number of classes and apparent complexity of the system.
  2. Encapsulate the current MyService class in another one, that has the responsibility of instantiating MyService, running it, and then returning the calculated value from it. This seems nice as the public API of the class is the same as the original and we happily use dependency-injection with no trouble.
  3. Let it be just as it is. If we try to run 2 concurrent calculations we may have concurrency problems. If we try to run the same method twice one after another, we may have problems with field reuse, also.

The second point seems a clear winner. Is there any other better alternative to point 2, or any of the shown points?

devoured elysium
  • 101,373
  • 131
  • 340
  • 557

2 Answers2

3

As described, the MyService class suffers from the Temporary Field code smell as described in Refactoring. Refactor the class and the problem goes away.

If this isn't possible, you'll need to make sure that each client receives a private instance of the service. All DI Containers support that via a lifetime style which is often called Transient.

As a third alternative, you can also use this solution.

Community
  • 1
  • 1
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • I do get why Temporary Field is a code smell for the general case. But notice that I'm considering the case of a single public method class, where I'm defining the data as fields precisely because they are being used in all the private methods (or at least, each field is being used in most of them). – devoured elysium Feb 21 '12 at 00:09
  • Also, in Java how would one achieve that Transient lifetime style with an IoC container without me having to define at least the interface of the factory (other than having to carry the IoC container around, which should of course be avoided)? – devoured elysium Feb 21 '12 at 00:17
  • As for the first comment, even if there's only a single public method, it's still a code smell, and the suggested refactoring is the same. As for the second question, as a corollary to the Composition Root pattern, if a client consumes a Transient service, the client must be Transient itself (unless you use the trick outlined in the third option in my answer). – Mark Seemann Feb 21 '12 at 01:10
1

Many containers for .NET support the automatic creation of factories. If you declare a constructor dependency

public MyConsumer(Func<MyService> factory) { ...}

and tell the container how to resolve MyServiceit would generate the Func<> part on its own.

Thus you don't need to create any classes that implement the factory. If you need runtime parameters passed to the constructor of MyService you could use something like Castle Windsor's Typed Factory Facilities or its port to Unity.

I would be really surprised if the Java containers don't provide similar features.


Update

What if each consumer needs more than one call to MyService.method()?

Store the factory in a private field of MyConsumer and use it whenever you need an instance of MyService. The container can be configured to return a new instance of MyService on every request.

public class MyConsumer
{
  private readonly Func<MyService> factory;
  public MyConsumer(Func<MySerivce> factory)
  {
    this.factory = factory;
  }
  public void NeedsMyServiceOnEveryCall(...)
  {
    var svc = factory();
    svc.Method();
  }
}
Sebastian Weber
  • 6,766
  • 2
  • 30
  • 49