Click here to Skip to main content
11,716,133 members (85,827 online)
Click here to Skip to main content

Service locator is not an anti pattern

, 1 Oct 2012 LGPL3 12.6K 7
Rate this:
Please Sign up or sign in to vote.
I'm getting really tired of all blog posts that states that service locator is an anti pattern. It's not.
This is an old version of the currently published technical blog.

I’m getting really tired of all blog posts that states that service locator is an anti pattern. It’s not. But let’s start by addressing all “proofs” of that. Here are some quotes from different blogs which can be found by Googling on “service locator anti pattern”.

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.

Reflection suffers from the exact same problem. It can be used incorrectly just as easy as the service locator pattern.

The problem with a Service Locator is that it hides dependencies in your code making them difficult to figure out and potentially leads to errors that only manifest themselves at runtime. If you use a Service Locator your code may compile but hide the fact that the Service Locator has been incorrectly configured. At runtime, when your code makes use of the Service Locator to resolve a dependency that hasn’t been configured, an error will occur. The compiler wasn’t able to help. Moreover, by using a Service Locator you can’t see from the API exactly what dependencies a given class may have.

Same problem. So what they are saying is that the pattern can hide dependencies and force you to run your application to discover it. I fully agree. It can do that.

Is it a problem?

So what’s the problem then. We have identified use cases where the pattern doesn’t fit. Does that make it an anti pattern? Of course not. Let’s examine when it’s perfectly valid.

Writing frameworks is a perfect example of where the service locator pattern shines. For instance. I’m writing a new library which is used to dispatch domain events and commands to their respective subscriber/handler. However, I do not want to force the developer to use a specific way of identifying those subscribers/handlers. Instead I want to let the developer choose.

The library got a facade which is used like this:

DomainEvent.Publish(new UserRegistered("Jonas Gauffin"))

To make that possible I’ve define a set of service location interfaces:

/// <summary>
/// Defines the actual service location
/// </summary>
public interface IServiceLocator
{
    /// <summary>
    /// Resolve all implementations
    /// </summary>
    /// <typeparam name="T">Service that we want implementations for.</typeparam>
    /// <returns>A collection of implementations; an empty collection if none is found.</returns>
    IEnumerable<T> ResolveAll<T>() where T : class;

    /// <summary>
    /// Get a specific service
    /// </summary>
    /// <typeparam name="T">Service to find</typeparam>
    /// <returns>Implementation</returns>
    T Resolve<T>() where T : class;
}

But since I want to allow the user to also use scoping (support objects with a limited lifetime) I’ve extended the SL interface:

/// <summary>
/// Facade for an inversion of control container.
/// </summary>
public interface IRootContainer : IServiceLocator
{
    /// <summary>
    /// Create a new child scope.
    /// </summary>
    /// <returns>A new child scope</returns>
    IScopedContainer CreateScope();
}

And the actual scope. Disposing it will dispose all located services in it.

/// <summary>
/// A scoped inversion of control container
/// </summary>
/// <remarks>It's purpose is to be able to store and return scoped services.</remarks>
public interface IScopedContainer : IDisposable, IServiceLocator
{
}

That service location is used inside a facade which looks like this (a bit simplified):

public class DomainEvent
{
    public static void Publish<T>(T domainEvent)
    {
        foreach (var handler in _serviceLocator.Resolve<ISubscribeOn<T>())
        {
            handler.Handle(domainEvent);
        }
    }
}

So why is it OK in this case? Because the dependencies are non-determistic. That is, we can’t beforehand know what kind of dependencies we should resolve when invoking the method.

Examples

Let’s go through some examples and see if they are proper usage or not. Let’s start by the most common example when saying that Service Location is an anti pattern.

public class SomeService
{
    public void DoSomething()
    {
        ServiceLocator.Resolve<ISomeRepository>().Save("kdd");
    }
}

Since we at beforehand know the dependency there is really no need to use the service locator pattern. Hence it’s improperly used. A better solution would have been to use dependency injection:

public class SomeService
{
    ISomeRepository _repos;
    
    public SomeService(ISomeRepository repos);
    {
        _repos = repos;
    }
    public void DoSomething()
    {
        _repos.Save("kdd");
    }
}

It’s better since we can by inspecting the class signature (as opposed to inspecting the implementation) can tell which dependencies the class have.

But what about this then:

public class SomeService
{
    public void DoSomething()
    {
        Resolve<ISomeRepository>().Save("kdd");
    }
    
    public void Resolve<T>()
    {
        return ServiceLocator.Resolve<T>();
    }
}

The Resolve() method is now non-determistic. So it’s perfectly fine. But the Something() method still know it’s dependency. Move the dependency to the constructor.

A common motivation to using the service locator pattern is this:

If I move all dependencies to the constructor I get a huge constructor that makes my class hard to use.

Well. Your class is not very SOLID. It’s probably something of a GOD class. Divide it into smaller classes.

Summary

My point is that you can abuse any pattern and that doesn’t make it an anti pattern. The reason to why Singleton and Service Locator got such a bad reputation is that they are easy to understand, implement and use. The problem is that the implementors/users haven’t fully understood the problem that the patters are trying to solve.

Update

Here is a challenge for all of you that claims that it’s an anti pattern:

Pretend that you are developer at Microsoft working with ASP.NET MVC. You want to let your framework users inject dependencies into the Controllers. But since you’ve read that service location is an anti pattern you’ll want to replace it with something else (which supports scoping).

Anyone of you that can present a solution which is cleaner than my defined interfaces above will get my eternal respect.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

Share

About the Author

jgauffin
Founder Gauffin Interactive AB
Sweden Sweden
Founder of OneTrueError, a .NET service which captures, analyzes and provide possible solutions for exceptions.

blog | twitter

You may also be interested in...

Comments and Discussions


Discussions posted for the Published version of this article. Posting a message here will take you to the publicly available article in order to continue your conversation in public.
 
QuestionArticle updated Pin
jgauffin3-Oct-12 2:48
memberjgauffin3-Oct-12 2:48 
QuestionShines... or blinds... Pin
ploeh2-Oct-12 9:38
memberploeh2-Oct-12 9:38 
AnswerRe: Shines... or blinds... Pin
jgauffin2-Oct-12 20:41
memberjgauffin2-Oct-12 20:41 
GeneralRe: Shines... or blinds... Pin
Mark Seemann2-Oct-12 21:53
memberMark Seemann2-Oct-12 21:53 
GeneralRe: Shines... or blinds... Pin
jgauffin2-Oct-12 21:58
memberjgauffin2-Oct-12 21:58 
GeneralRe: Shines... or blinds... Pin
Mark Seemann4-Oct-12 6:59
memberMark Seemann4-Oct-12 6:59 
GeneralRe: Shines... or blinds... Pin
jgauffin4-Oct-12 7:17
memberjgauffin4-Oct-12 7:17 
QuestionService Locater an anti pattern Pin
Martin Bohring2-Oct-12 5:59
memberMartin Bohring2-Oct-12 5:59 
AnswerRe: Service Locater an anti pattern Pin
jgauffin2-Oct-12 6:11
memberjgauffin2-Oct-12 6:11 
QuestionServiceLocators are not the same as IoC containers Pin
John Brett2-Oct-12 2:12
memberJohn Brett2-Oct-12 2:12 
AnswerRe: ServiceLocators are not the same as IoC containers Pin
jgauffin2-Oct-12 2:21
memberjgauffin2-Oct-12 2:21 
GeneralRe: ServiceLocators are not the same as IoC containers Pin
John Brett3-Oct-12 1:31
memberJohn Brett3-Oct-12 1:31 
GeneralRe: ServiceLocators are not the same as IoC containers Pin
jgauffin3-Oct-12 1:39
memberjgauffin3-Oct-12 1:39 
GeneralRe: ServiceLocators are not the same as IoC containers Pin
jgauffin3-Oct-12 3:52
memberjgauffin3-Oct-12 3:52 
QuestionSubscribersResolver instead of ServiceLocator Pin
Michał Zalewski2-Oct-12 1:53
memberMichał Zalewski2-Oct-12 1:53 
AnswerRe: SubscribersResolver instead of ServiceLocator Pin
jgauffin2-Oct-12 1:55
memberjgauffin2-Oct-12 1:55 
QuestionDoubts Pin
Helluin1-Oct-12 11:03
memberHelluin1-Oct-12 11:03 
AnswerRe: Doubts Pin
jgauffin1-Oct-12 18:40
memberjgauffin1-Oct-12 18:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150901.1 | Last Updated 1 Oct 2012
Article Copyright 2012 by jgauffin
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid