Pregunta

Supongamos que tengo una clase llamada PermissionManager que solo debería existir una vez para mi sistema y básicamente cumple con la función de administrar varios permisos para varias acciones en mi aplicación. Ahora tengo alguna 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 habría hecho que mi clase llamara al siguiente pseudo-código en algún lugar:

     PermissionManager.getInstance().isReadPermissionEnabled(this)

Pero como me he dado cuenta de que todos aquí odian 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 singletons parecen tener sentido (no verificable, alto acoplamiento, etc.) .

¿Entonces debo exigir que los usuarios de la API pasen una instancia de PermissionManager en el constructor de la clase? ¿Aunque solo deseo que exista una única instancia de PermissionManager para mi aplicación?

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


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

¿Fue útil?

Solución

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

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

Está en lo cierto al afirmar que normalmente es difícil 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 use un PermissionManager).

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

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

Por supuesto, estrictamente hablando, su PermissionManager debe implementar algún tipo de interfaz de IPermissionManager, y eso es lo que su otra clase debe hacer referencia para que una implementación ficticia pueda sustituirse más fácilmente durante las pruebas.

Otros consejos

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 utilicen un método de fábrica o un resumen de fábrica. O puede agregar un constructor sin parámetros para que ellos llamen y le inyecten el PermissionManager mientras que sus pruebas usan otro constructor que puede usar para burlarse del PermissionManager.

El desacoplamiento de sus clases hace que sean más flexibles, pero también puede hacer que sean más difíciles de usar. Depende de la situación lo que necesites. Si solo tiene un PermissionManager y no tiene problemas en probar las clases que lo usan, 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.

Si se está suscribiendo a la forma de hacer la inyección de dependencia para hacer las cosas, las clases que necesiten su PermissionManager deberían tenerla inyectada como una instancia de objeto. El mecanismo que controla su creación de instancias (para imponer 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 cumplimiento. Si está haciendo su cableado de objetos a mano, la inyección de dependencia favorece el código de agrupación que hace que la creación de instancias (nuevo operador funcione) fuera de su lógica empresarial.

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

Estas publicaciones me han sido reveladoras en el pasado:

  

¿Entonces debo exigir que los usuarios de la API pasen una instancia de PermissionManager en el constructor de la clase? ¿Aunque solo deseo que exista una única 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, lo ideal sería tener la dependencia de una interfaz de IPermissionsManager para reducir aún más el acoplamiento. Supongo que esta es la mejor práctica en Java también.

El patrón de singleton no es malo por 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 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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top