본문 바로가기
유니티/개념 정리

Service Locator

by fore4022 2025. 8. 16.

 우선, 앞서서 Service Locator는 안티 패턴이라는 평가를 받고 있다는 것을 짚고 가겠다.


 우선 Service Locator의 Service에 대해서 알아보겠다.

Service

 인터페이스에 정의된 기능을 미리 구현하거나, 공통된 기능을 묶어서 만든 클래스이다.

Service Locator란?

  •  인터페이스 구현부에서 요청한 서비스를 제공하는 정적 클래스(객체)이다.
  •  필요에 의해서 서비스를 생성한다. 생성된 모든 서비스를 Service Locator에서 관리한다.
  •  서비스는 타입당 1개만 생성되며, 같은 타입의 서비스는 기존에 생성된 객체(서비스)로 대체한다.
  •  생성한 서비스를 이용하지 않더라도, 서비스 객체를 제거하지 않는다.

Service Locator의 단점

  1.  Service Locator는 항상 사용되지 않는 서비스를 포함한, 모든 서비스를 가지고 있다는 것이다.
  2.  한개의 서비스가 많은 의존성을 가질 수 있다. 실행에 따라서 동작이 달라지는 기능과 같은 경우에 모두 똑같은 서비스에 의존함으로, 의도하지 않은 실행의 차이가 생길 수 있다.
  3.  외부에서 구현에 필요한 서비스를 제공하는 것이 아닌, 스스로 서비스를 가져오는 방식으로 구현되기 때문에, 결합도가 높다.
  4.  결합도와 의존성이 높아서, 수정이 어렵다.

 물론 여기서 이런 생각이 들 수 있다.

"Service Locator객체를 만들고 외부에서 의존성을 주입해 주면 되는거 아닌가요?"

 위의 질문에 대한 답으로, 그렇게 구현하게 된다면 아래와 같다.

(구현 클래스) <- (구현 클래스가 의존할 클래스), (구현 클래스의 의존성 주입을 위한 클래스)

 결과적으로 의존성을 외부에 돌리는 것으로, 클래스 하나만 더 생기게 된다.

 물론, 코드를 어떻게 작성하는지에 따라서 위의 단점이 나타나지 않을 수 있다. 하지만, 그렇다면 우리는 구현을 강제하는 인터페이스 또한 사용하는 의미가 퇴색될 것이다.

 이미 위에서 나열된 단점들만 보더라도, 휴먼 에러의 가능성이 많으며, 많은 개발자가 참여하는 협업 환경에서는 더욱 알맞지 않다는 것을 알 수 있다. 심지어 강한 결합도와 의존성에 의해 수정이 어렵다는 부분은, 추후 기능의 변경이나 추가를 고려했다고 볼 수 없기 때문에, 객체지향의 5원칙 중에서 Open-Closed 원칙에 위배된다.


대안

 Service Locator의 대안으로는 DI(Dependency Injection)를 사용하는 것이 일반적으로 자리 잡았다.

Dependency Injection

 구현에서 사용된 서비스만 존재한다, 같은 서비스 인스턴스를 공유하지 않으므로, 실행결과가 확실하고 일관되게 유지할 수 있다. 강한 의존성과 높은 결합도는 의존성을 외부에서 받는 방식으로, 서비스에 구애받지 않도록 하였다.

 확실하게 Service Locator의 단점을 장점으로 가지는 방식이다. 이로 인해서 Service Locator를 써야할 이유는 더 없다고 보아도 될 것이다.


Service Locator 구현 예시

 간단히 구현한 예시로, 기본적인 구현만 포함하고 있습니다.

public static class ServiceLocatorContainer
{
	private static Dictionary<Type, object> services = new();
	
	public static void Register<T>() where T : new()
	{
		Type t = typeof(T);
		
		if(!services.ContainsKey(t))
		{
			T instance = new();
		
			services.Add(t, instance);
		}
	}
	public static T Get<T>() where T : new()
	{
		Type t = typeof(T);
	
		if(!services.ContainsKey(t))
		{
			Register<T>();
		}
		
		return (T)services[t];
	}
}
public class Service : IServiceProvider
{
	public void Method_A()
	{
		Debug.Log("Hello, ");
	}
	public void Method_B()
	{
		Debug.Log("World!");
	}
}
public interface IServiceProvider
{
	public void Method_A();
	public void Method_B();
}
public class TestClass : MonoBehaviour, IServiceProvider
{
	private IServiceProvider serviceProvider;
	
	public void Method_A()
	{
		serviceProvider.Method_A();
	}
	public void Method_B()
	{
		serviceProvider.Method_B();
	}
	private void Awake()
	{
		ServiceLocatorContainer.Register<Service>();
		
		serviceProvider = ServiceLocatorContainer.Get<Service>();
	}
	private void Start()
	{
		Method_A();
		Method_B();
	}
}

마무리하며

 아무리 조심히 사용하더라도, 휴먼에러의 가능성을 무시할 수 없기 때문에, 저 같이 개발을 공부하는 학생이 사용하기에 좋지 않은 것 같다. 그저 ‘Service Locator라는 개념도 있구나.’ 정도로 받아들여 주셨으면 좋겠다.

 현실적으로 문제 상황을 직면했을 때는 Dependency Injection을 이용해서 문제를 해결하기 바란다.

'유니티 > 개념 정리' 카테고리의 다른 글

Internal  (0) 2025.09.29
Dependency Injection  (0) 2025.07.10
확장 메서드  (3) 2025.07.02
메서드 체이닝  (0) 2025.06.30
SerializedProperty  (0) 2025.04.28