design dependency-injection singleton

design - Pregunta Práctica Singleton & Dependen Injection



dependency-injection (5)

Digamos que tengo una clase llamada PermissionManager que solo debería existir una vez para mi sistema y básicamente cumple la función de administrar varios permisos para varias acciones en mi aplicación. Ahora tengo una clase en mi aplicación que necesita poder verificar un cierto permiso en uno de sus métodos. El constructor de esta clase es actualmente público, es decir, utilizado por los usuarios de la API.

Hasta hace un par de semanas, simplemente hice que mi clase llamara al siguiente pseudocódigo en alguna parte:

PermissionManager.getInstance().isReadPermissionEnabled(this)

Pero como he notado que todos odiaban los singletons + este tipo de acoplamiento, me preguntaba cuál sería la mejor solución, ya que los argumentos que he leído en contra de los singleton parecen tener sentido (no se pueden probar, son de alto nivel de acoplamiento, etc.).

Entonces, ¿realmente debería exigir a los usuarios de API pasar una instancia de PermissionManager en el constructor de la clase? Aunque solo quiero una instancia de PermissionManager para mi aplicación.

¿O me estoy equivocando y debería tener un constructor no público y una fábrica en algún lugar que me pase en la instancia de PermissionManager?

Información adicional Tenga en cuenta que cuando digo "Inyección de dependencia", estoy hablando del patrón DI ... No estoy usando ningún marco DI como Guice o Spring. (...todavía)


Entonces, ¿realmente debería exigir a los usuarios de API pasar una instancia de PermissionManager en el constructor de la clase? Aunque solo quiero una instancia de PermissionManager para mi aplicación.

Sí, esto es todo lo que necesitas hacer. Si una dependencia es un singleton / por solicitud / por hilo o un método de fábrica es responsabilidad de su contenedor y configuración. En el mundo .net, idealmente tendremos la dependencia de una interfaz IPermissionsManager para reducir aún más el acoplamiento, supongo que también es una buena práctica en Java.


De hecho, puede comenzar inyectando el PermissionManager. Esto hará que tu clase sea más comprobable.

Si esto causa problemas a los usuarios de esa clase, puede hacer que usen un método de fábrica o una fábrica abstracta. O bien, puede agregar un constructor sin parámetros para que ellos lo invoquen e inyecte el PermissionManager mientras sus pruebas usan otro constructor que puede usar para simular el PermissionManager.

Desacoplando sus clases más hace que sus clases sean más flexibles, pero también puede hacer que sean más difíciles de usar. Depende de la situación lo que necesitará. Si solo tiene un PermissionManager y no tiene problemas para probar las clases que lo usan, entonces no hay razón para usar DI. Si desea que las personas puedan agregar su propia implementación de PermissionManager, DI es el camino a seguir.


El patrón singleton no es malo en sí mismo, lo que lo hace feo es la forma en que se usa comúnmente, ya que es el requisito de querer solo una instancia única de una determinada clase, lo que creo que es un gran error.

En este caso, convertiría a PermissionManager en una clase estática a menos que, por algún motivo, necesite que sea un tipo instanciable.


Si está utilizando una infraestructura de inyección de dependencias, la forma más común de manejar esto es pasar un objeto PermissionsManager en el constructor o tener una propiedad de tipo PermissionsManager que la estructura establezca para usted.

Si esto no es factible, hacer que los usuarios obtengan una instancia de esta clase a través de la fábrica es una buena opción. En este caso, la fábrica pasa el PermissionManager al constructor cuando crea la clase. En la puesta en marcha de la aplicación, debe crear primero el Administrador de permisos único, luego crear su fábrica y pasar el Administrador de permisos.

Tiene razón en que normalmente es difícil de manejar para los clientes de una clase saber dónde encontrar la instancia correcta de PermissionManager y pasarla (o incluso preocuparse por el hecho de que su clase utiliza un PermissionManager).

Una solución de compromiso que he visto es otorgar a su clase una propiedad de tipo PermissionManager. Si la propiedad se ha configurado (por ejemplo, en una prueba de unidad), se usa esa instancia, de lo contrario se utiliza el singleton. Algo como:

PermissionManager mManager = null; public PermissionManager Permissions { if (mManager == null) { return mManager; } return PermissionManager.getInstance(); }

Por supuesto, estrictamente hablando, su Administrador de Permisos debería implementar algún tipo de interfaz IPermissionManager, y eso es lo que su otra clase debería hacer para que una implementación ficticia pueda ser sustituida más fácilmente durante la prueba.


Si se suscribe a la manera de hacer las cosas con la inyección de dependencias, cualquiera que sea la clase que necesite, su PermissionManager debe hacer que se la inyecte como una instancia de objeto. El mecanismo que controla su creación de instancias (para hacer cumplir la naturaleza de singleton) funciona en un nivel superior. Si utiliza un marco de inyección de dependencia como Guice, puede hacer el trabajo de aplicación. Si está haciendo su cableado de objetos a mano, la inyección de dependencia favorece la agrupación del código que hace la instanciación (nuevo trabajo del operador) lejos de su lógica comercial.

De cualquier manera, sin embargo, el clásico "capital-S" Singleton generalmente se ve como un antipatrón en el contexto de la inyección de dependencia.

Estas publicaciones han sido muy útiles para mí en el pasado: