Course contentsShow
← Unity Game Development
Lesson 448 of 8287. Advanced Game ArchitectureFree lesson

Decoupling Systems with the Service Locator Pattern

You will build a central registry to provide global access to services, reducing direct dependencies between disparate game systems and managers.

In this lesson, you will learn how to create a central "registry" that allows your game systems to find and use services without needing to know exactly where those services live or how they are constructed.

The Problem: Tight Coupling

When your PlayerController needs to access an AudioSystem, a SaveManager, or a DialogueManager, it often requires direct references. You might find yourself using FindObjectOfType<AudioSystem>() or dragging components into inspector slots. This creates "spaghetti" code where changing one system breaks everything else.

The Solution: The Service Locator

The Service Locator pattern acts as a middleman. Instead of systems looking for each other, they register themselves with a central ServiceLocator at startup. Any other system that needs a service simply asks the locator: "Give me the IAudioService."

Here is how a basic implementation looks:

public static class ServiceLocator {
    private static readonly Dictionary<System.Type, object> _services = new();

    public static void Register<T>(T service) => _services[typeof(T)] = service;

    public static T Get<T>() => (T)_services[typeof(T)];
}

Putting it into Practice

  1. Define an Interface: Create an IAudioService interface. This ensures your systems depend on an abstraction rather than a concrete implementation (adhering to our previous lessons on the Dependency Inversion Principle).
  2. Register the Service: In your GameInitializer script, instantiate your AudioManager and call ServiceLocator.Register<IAudioService>(myAudioManager).
  3. Access the Service: Anywhere in your codebase, you can now write var audio = ServiceLocator.Get<IAudioService>(); to access the functionality immediately.

Why this matters

By using this pattern, your PlayerController no longer cares if the AudioSystem is a MonoBehaviour in the scene, a plain C# class, or a mocked-up version used for unit testing. You’ve successfully decoupled the request for a service from the existence of the service itself. This makes your architecture modular, testable, and significantly easier to refactor as your project grows.

Key Takeaway: The Service Locator pattern replaces direct hard-coded references with a dynamic registry, allowing disparate systems to communicate through clean, loosely-coupled interfaces.