Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Service Locator Pattern

Intent

Provide a global point of access to a service without the consumer having to know how to construct it. The service locator acts as a registry that maps interfaces to concrete implementations.

How It Works

class ServiceLocator:
    _services = {}

    @classmethod
    def register(cls, interface, implementation):
        cls._services[interface] = implementation

    @classmethod
    def get(cls, interface):
        if interface not in cls._services:
            raise ValueError(f'No service registered for {interface}')
        return cls._services[interface]()

# Registration (typically at app startup)
ServiceLocator.register(ILogger, FileLogger)
ServiceLocator.register(IDatabase, PostgresDB)

# Usage
logger = ServiceLocator.get(ILogger)
logger.log('Hello')

Service Locator vs Dependency Injection

AspectService LocatorDependency Injection
Who resolves deps?Consumer asks for themFramework/container provides them
CouplingConsumer depends on the locatorConsumer depends only on abstractions
TestabilityHarder to swap in testsEasy to inject mocks via constructor
VisibilityDependencies hidden in method bodiesDependencies explicit in constructors
Compile-time safetyRuntime errors for missing servicesCompile-time errors (constructor params)

Why It’s Considered an Anti-Pattern

  1. Hidden dependencies: Reading a class doesn’t reveal what services it needs — they’re buried in method calls.
  2. Runtime failures: A missing registration causes a runtime crash, not a compile error.
  3. Tight coupling to the locator itself: Every consumer imports the ServiceLocator.
  4. Testability friction: Tests must set up the global registry instead of passing mocks directly.

When to Use Anyway

  • Migrating a legacy codebase to DI incrementally (locator as an intermediate step).
  • Frameworks where DI containers aren’t available (e.g., constrained embedded environments).
  • Plugin architectures where dynamic registration is a core requirement.

Interview Questions

Q: Why is service locator often called an anti-pattern? A: It hides dependencies (not visible at construction), introduces runtime coupling to the locator, and makes testing harder. DI makes dependencies explicit in constructors, enables compile-time checking, and simplifies unit testing with injected mocks.

Q: Can service locator and DI coexist? A: Yes, in practice they often do during migrations. Use DI for new code and the service locator for legacy modules. Gradually refactor locators into constructor-injected dependencies.

References