简体   繁体   中英

Dependency injection or service location?

I'm trying to learn dependency injection, and there are many subtleties to it I'm yet to grasp. One of the books that I've started reading for that purpose is " Foundations of Programming " by Karl Seguin. There's an example about dependency injection:

public class Car
{
    private int _id;

    public void Save()
    {
        if (!IsValid())
        {
            //todo: come up with a better exception
            throw new InvalidOperationException("The car must be in a valid state");
        }

        IDataAccess dataAccess = ObjectFactory.GetInstance<IDataAccess>();
        if (_id == 0)
        {
            _id = dataAccess.Save(this);
        }
        else
        {
            dataAccess.Update(this);
        }
    } 
}

And then he goes ahead and suggest adding another level of indirection, rather than calling ObjectFactory directly in the method:

public static class DataFactory
{
    public static IDataAccess CreateInstance
    {
        get
        {
            return ObjectFactory.GetInstance<IDataAccess>();
        }
    }
}

But isn't this "Service Location" in fact?

It is service locator. There are several of ways to use dependency:

  • aggregation (example case)

  • composition

    • DI in constructor, mandatory (could be injected using SL on upper level)

    • DI in property, optional (could be injected using SL on upper level)

What to choose depends on many factors, for example whether it is stable or unstable dependency, whether you need to mock it in tests or not etc. There is good book on DI called 'Dependency Injection in .NET' by Mark Seemann.

Yes, looks like SL to me. Dependency injection traditionally follows one of two patterns; property injection or constructor injection.

Dependency injection feels more effort than service location at first, but service location (SL) has a number of negatives. It is far too easy with a service locator to just go crazy requesting services on a whim, all over the place. This is fine until you go to refactor and realise the coupling is "too damn high".

With DI I prefer the constructor injection form because it forces me to think up front about who needs what.

That all said, my current project was started as a green field project using a service locator because it gave me the flexibility "not" to think about dependencies and to let the application shape evolve. Latterly I've been refactoring to use DI, mainly to get a handle on what relies on what and why.

Your example is ServiceLocator. There is always a ServiceLocator somewhere. I would say the key is to understanding why you would use it directly and why ideally you might not have to.

The key concept is the dependency inversion principal. Dependency injection and inversion of control frameworks are tools that facilitate application of the principal. Ideally you want your objects constructor parameters to be interface definitions which will be resolved at object creation time.

If you are using modern tools, such as asp.net MVC then you have access to what is called the composition root which is the entry point of the application. In MVC it's controller. Since you have access to the composition root you don't need to use ServiceLocator because injection is driven from the top for you by your IOC framework which you would have registered and setup. Basically your controller has constructors parameters like ISomeService which is registered with IOC and injected automatically when the controller instance is created. If the ISomeService had some dependencies they would also be in the constructor as ISomeUtility, and so forth as your objects get deeper and deeper. This is ideal and you would never have need to use the ServiceLocator to resolve an object.

If you were in a situation using technology that doesn't grant you access to the root or if you were wanting to start using an IOC framework in an application that didn't have one and you were adding it for the first time then you may find you can't get to the composition root. It could be a limitation of the framework or the quality of the code. In these cases you have to use the ServiceLocator or directly create the object yourself. In these cases using the ServiceLocator is OK and is better than creating that object yourself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM