Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it bad to use servicelocation instead of constructor injection to avoid writing loads of factory classes

Right now we use DI/IOC and when we need to pass extra parameters to a constructor we use a factory class e.g.

public class EmailSender 
{
    internal EmailSender(string toEmail, string subject,String body, ILogger emailLogger)
    {.....} 
}

public class EmailSenderFactory
{
    ILogger emailLogger;
    public EmailSenderFactory(ILogger emailLogger)
    { 
        this.emailLogger = emailLogger;
    }
    public EmailSender Create(string toEmail, string subject, string body) 
    {
        return new EmailSender(toEmail, subject, body, emailLogger);
    }
}

Now the problem with this is that we end up creating a whole lotta factory classes, and people don't always know to use them (they sometimes new them up themselves). What are the biggest negatives of coding the class like this:

public class EmailSender 
{
    EmailLogger logger = IoC.Resolve<ILogger>();
    internal EmailSender(string toEmail, string subject,String body)
    {.....} 
}

Pro: we now can use the constructor safely without needing a factory class Con: we have to reference the Service Locator (I'm not worried about testability, its easy to use a mock container as the backing service for the container).

Is there some big stinker of a reason out there why we shouldn't do this?

edit: after a bit of thought, I twigged that by having a private constructor, and by nesting the Factory class, I could keep the implementation and factory together, and prevent people from creating classes improperly, so the question has become somewhat moot. All the points points about SL being dirty, are of course true, so the solution below keeps me happy:

public class EmailSender 
{
    public class Factory
    {
        ILogger emailLogger;
        public Factory(ILogger emailLogger)
        { 
            this.emailLogger = emailLogger;
        }
        public EmailSender Create(string toEmail, string subject, string body) 
        {
            return new EmailSender(toEmail, subject, body, emailLogger);
        }
    }
    private EmailSender(string toEmail, string subject,String body, ILogger emailLogger)
    {
    } 
}
like image 641
mcintyre321 Avatar asked Oct 21 '09 09:10

mcintyre321


People also ask

Which is better constructor injection or setter injection?

If we use both constructor and setter injection, IOC container will use the setter injection. Changes: We can easily change the value by setter injection. It doesn't create a new bean instance always like constructor. So setter injection is flexible than constructor injection.

Why constructor injection is better than field injection?

Immutability. Constructor injection helps in creating immutable objects because a constructor's signature is the only possible way to create objects. Once we create a bean, we cannot alter its dependencies anymore.

Why is Servicelocator bad?

In short, the problem with Service Locator is that it hides a class' dependencies, causing run-time errors instead of compile-time errors, as well as making the code more difficult to maintain because it becomes unclear when you would be introducing a breaking change.

What is the limitation of constructor injection?

The main disadvantage to Constructor Injection is that if the class you're building is called by your current application framework, you might need to customize that framework to support it. Some frameworks assume that your classes will have a parameterless constructor.


2 Answers

yes - it is bad.

  • Why write all that code when you can have the framework do the work? All the IoC.Resolve() calls are superfluous and you shouldn't have to write them.
  • Another, even more important aspect, is that your components are tied to your service locator.

    You're now unable to instantiate them just like that - you need a completely set up service locator in place every time you need to use a component.

  • Last but, bot least - your SL code is sprinkled all over your codebase which is not a good thing, because when you want to change something, you have to look in multiple places.
like image 187
Krzysztof Kozmic Avatar answered Sep 19 '22 18:09

Krzysztof Kozmic


The largest reason I can think of (without just looking at issues with Service Locators in general) is that it is not what I as a user of your class would expect.

Meta discussion:
Some DI frameworks (Guice for example) will build the factory for you.

Some people advocate separating the "newable" from the "injectable".

like image 40
Michael Lloyd Lee mlk Avatar answered Sep 18 '22 18:09

Michael Lloyd Lee mlk