0

I'm refactoring an old app to use dependency injection.n I'm pretty new to DI.

I have a class that used to be a singleton. I'm refactoring it into a non-singleton class and using the container to manage its lifetime (as a single instance). It has some initialization that used to be done in the constructor but it seems that this is generally frowned-on in the DI world: SRP says methods should just do one thing and so constructors are just for dependencies, I read somewhere.

If the class had no dependencies, I could just create the instance, call .Initialize() and register the instance with the container as a singleton. But the class has a dependency which I'd prefer to resolve using the container.

Am I going about this the wrong way? Am I missing some pattern?

1

"SRP says methods should do just one thing". True. Constructors should do just one thing, and that is to put the object into a usable state. If just storing the dependencies doesn't put the object into a usable state, then the constructor isn't doing it's job.

Did you read anywhere that "constructors with dependency injection should only set the dependencies, and shouldn't do anything else"? I don't think so.

  • 1
    It took me a while to find it again: Mark Seeman's Dependency Injection in .NET., p.99. – user2871239 Jun 27 '15 at 6:44
0

Not sure what language you are using, so I'm using pseudo-C# as example.

You can create an IInitializes interface, which you then call after the instances are created.

public interface IInitializes
{
   void Initialize();
}

public class PreviousSingleton : IPreviousSingleton, IInitializes
{
    IDependency dep;

    public PreviousSingleton(IDependency dep)
    {
        this.dep = dep;
    }

    public void Initialize() {
        // do whatever with dep
    }
}

Then when you register and create it using IoC :

IoC ioc;
ioc.RegisterAsSingleton<PreviousSingleton>(); // make sure IoC recognizes it as both having IPreviousSingleton and IInitializes interfaces

// do rest of the registrations

// and after registrations are done, run initialization
var instancesToInitialize = ioc.GetAllInstances<IInitializes>();
foreach(var inst in instancesToInitialize)
{
    inst.Initalize();
}

var noLongerSingleton = ioc.GetInstance<IPreviousSingleton>(); // should be initialized now

This works, because only one instance will be kept inside IoC, which means same instance will be initialized as one that will be passed to other objects. Also works if you have multiple different classes implementing IInitializes.

0

"It has some initialization that used to be done in the constructor but it seems that this is generally frowned-on in the DI world" - that's not exactly true. DI is just about providing dependencies externally not creating them within an object.

So first thing fo you is to identify, within your singleton, what are it's dependencies and which are other object that it just uses to execute it's logic but they don't need to be created externally.

For example, say you have you OldSingletonClass which uses instances of C1 and C2 classes, that have their own dependencies. These should obviously be injected. But say that this class is supposed to make some HTTP calls and you implemented it with a some HttpClient and this HttpClient does not take any dependencies. I'd say that in this case you can safely create it in constructor (if it of course makes sense to keep single instance).

As for creating stuff in constructor vs Initialize() method - my experience is it is sometimes discouraged to do too much stuff in ctor because of different object inheritance issues, but other than that it's just a matter of style Last thing, remember that DI does not require to use DI-container. It is often very helpful if you're working with tons of objects and some frameworks that "magically" create new instances (ASP.NET MVC controllers for example), but in case that you have, say, 20 objects, all created at application startup, I find it is often much cleaner to wire them together in code.

  • 1
    If the HttpClient is created in constructor how can the class be unit tested? – Esben Skov Pedersen Jun 24 '15 at 13:52
  • good point, of course you can wrap the HttpClient into IHttpClientService but then how do you test an implementation of this IHttpClientService? and just btw, how do you test HttpClient itself? you can abstract TcpSocket obviously, but then how do you test TcpSocket and so on. I guess that at some level it might be easier to run local mock http server and feed data through it. Same goes with testing code that interacts with database. It might be easier to assume that db just works and feed test data to it. – Łukasz Zwierko Jun 24 '15 at 19:51
  • The point is you can unit test a class using a http client. It is not the http client we want to test. The real IHttpClientService implementation will not be unit tested but integration tested. That way we can unit test all the important parts in isolation and keep integration testing to a minimum. – Esben Skov Pedersen Jun 25 '15 at 5:16
  • 1
    I guess you're right, it is a better approach obviously. – Łukasz Zwierko Jun 25 '15 at 9:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.