Recientemente leí el artículo de Mark Seemann sobre el antipatrón del Localizador de servicios.
El autor señala dos razones principales por las que ServiceLocator es un antipatrón:
Problema de uso de la API (con el que estoy perfectamente de acuerdo)
Cuando la clase emplea un localizador de servicios, es muy difícil ver sus dependencias ya que, en la mayoría de los casos, la clase solo tiene un constructor PARAMETERLESS. A diferencia de ServiceLocator, el enfoque DI expone explícitamente las dependencias a través de los parámetros del constructor para que las dependencias se vean fácilmente en IntelliSense.Problema de mantenimiento (que me desconcierta)
Considere el siguiente ejemplo
Tenemos una clase 'MyType' que emplea un enfoque de localización de servicios:
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
}
}
Ahora queremos agregar otra dependencia a la clase 'MyType'
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
// new dependency
var dep2 = Locator.Resolve<IDep2>();
dep2.DoSomething();
}
}
Y aquí es donde comienza mi malentendido. El autor dice:
Se vuelve mucho más difícil saber si está introduciendo un cambio importante o no. Debe comprender toda la aplicación en la que se utiliza el Localizador de servicios, y el compilador no lo ayudará.
Pero espere un segundo, si estuviéramos usando el enfoque DI, introduciríamos una dependencia con otro parámetro en el constructor (en caso de inyección del constructor). Y el problema seguirá ahí. Si nos olvidamos de configurar ServiceLocator, entonces podemos olvidar agregar una nueva asignación en nuestro contenedor IoC y el enfoque DI tendría el mismo problema de tiempo de ejecución.
Además, el autor mencionó las dificultades de las pruebas unitarias. Pero, ¿no tendremos problemas con el enfoque DI? ¿No necesitaremos actualizar todas las pruebas que instanciaron esa clase? Los actualizaremos para pasar una nueva dependencia simulada solo para que nuestra prueba sea compilable. Y no veo ningún beneficio de esa actualización y gasto de tiempo.
No estoy tratando de defender el enfoque del Localizador de servicios. Pero este malentendido me hace pensar que estoy perdiendo algo muy importante. ¿Alguien podría disipar mis dudas?
ACTUALIZACIÓN (RESUMEN):
La respuesta a mi pregunta "¿Es el localizador de servicios un antipatrón" realmente depende de las circunstancias. Y definitivamente no sugeriría tacharlo de su lista de herramientas. Puede ser muy útil cuando comienzas a lidiar con código heredado. Si tiene la suerte de estar al comienzo de su proyecto, entonces el enfoque DI podría ser una mejor opción ya que tiene algunas ventajas sobre el Localizador de servicios.
Y aquí están las principales diferencias que me convencieron de no usar Service Locator para mis nuevos proyectos:
- Lo más obvio e importante: Service Locator oculta las dependencias de clase
- Si está utilizando algún contenedor de IoC, es probable que escanee todo el constructor al inicio para validar todas las dependencias y le dará comentarios inmediatos sobre las asignaciones faltantes (o la configuración incorrecta); Esto no es posible si está utilizando su contenedor IoC como Localizador de servicios
Para más detalles lea las excelentes respuestas que se dan a continuación.