2008-10-29 9 views
15

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.Pregunta práctica de Singleton & Dependen Injection

Hasta hace un par de semanas, tendría que simplemente tenía mi clase de llamar al siguiente pseudo-código en algún lugar:

 PermissionManager.getInstance().isReadPermissionEnabled(this) 

Pero ya que he notado aquí todos odiando únicos + este tipo de acoplamiento, que estaba preguntándome cuál sería la mejor solución, ya que los argumentos que he leído contra los singleton parecen tener sentido (no comprobables, de acoplamiento alto, etc.).

¿Debo exigir realmente a los usuarios de API que pasen una instancia de PermissionManager en el constructor de la clase? Aunque solo quiero una instancia de PermissionManager para mi aplicación.

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


Otros detalles Tenga en cuenta que cuando digo "inyección de dependencias", estoy hablando de la DI Pattern ... No estoy usando cualquier marco DI como Guice o primavera. (... todavía)

Respuesta

3

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 al decir 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 dar a su clase una propiedad del 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 así 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 IPermissionManager y que es lo que su otra clase debería hacer referencia a lo que una aplicación ficticia puede ser sustituido más fácilmente durante la prueba.

+1

El punto sobre la inyección a través de una interfaz es muy importante. La capacidad de burlarse del objeto PermissionManager en las pruebas es lo que hace que DI sea un enfoque poderoso para obtener códigos más comprobables. –

+1

¿Qué ocurre si PermissionManager tiene una dependencia? ¿Hay una manera menos extraña que PermissionManager.getInstance (Foo)? ? –

0

El patrón singleton no está nada mal en sí mismo, lo que lo hace feo es la manera en que se usa comúnmente, como el requisito de querer solo una instancia de cierta clase, que creo que es gran error.

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

2

usted realmente puede comenzar mediante la inyección de la PermissionManager. Esto hará que tu clase sea más comprobable.

Si esto causa problemas para los usuarios de esa clase puede hacer que se utilizan un método de fábrica o de 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.

desacoplamiento sus clases más hace que sus clases sean más flexibles, pero también puede hacer que sea más difícil 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 ninguna razón para usar DI. Si desea que las personas puedan agregar su propia implementación de PermissionManager, DI es el camino a seguir.

2

Si se suscribe a la manera de hacer las cosas con la inyección de dependencia, cualquiera que sea la clase que necesite su PermissionManager debe tenerla inyectada 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, los clásicos "de capital-S" Singleton es generalmente visto como un anti-patrón en el contexto de la inyección de dependencia.

Estos mensajes han sido perspicaz para mí en el pasado:

1

Así que debo en realidad requieren que los usuarios de la API para pasar en una instancia PermissionManager en el constructor ¿de la clase? Aunque solo quiero una instancia de PermissionManager para mi aplicación.

Sí, esto es todo lo que tiene que 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.

Cuestiones relacionadas