2009-06-10 10 views
7

He estado leyendo acerca de la inyección de dependencia y tengo una pregunta simple. Puedo entender cómo, a través de la inyección de constructores o del sistema, las dependencias requeridas son autoconectadas por el marco DI. ¿Qué sucede cuando un objeto decide que necesita crear un nuevo objeto debido a algún proceso comercial? ¿Necesito siempre crear una fábrica en estas situaciones? Para que sea una pregunta menos abstracta, aquí hay un ejemplo.Pregunta de novato sobre Dependency Injection cuando un método necesita crear objetos nuevos

Digamos que estoy escribiendo un juego de Asteriods. Hay un barco en el medio que puede girar y disparar a los asteroides. Supongamos que el barco ha sido creado y se han inyectado cosas apropiadas. Cuando se llama al playerShip.shoot(), necesitamos crear un objeto bullet. El objeto de viñeta necesita saber hacia dónde va (direction) y dónde comenzar (point).

Normalmente, me gustaría hacer algo como esto:

bullet = new Bullet(direction, point); 

Sin embargo, las parejas que firmemente la clase PlayerShip a la clase de bala. ¿Cómo debería funcionar esto bajo inyección de dependencia? ¿Necesito crear una interfaz BulletFactory e inyectar una implementación de eso en la nave?

Editar: En realidad, no estoy escribiendo asteriods. Este fue un ejemplo simple que pensé que la gente entendería. Quería algo que necesitara ser creado un tiempo de ejecución (no mientras "conectaba objetos") que también tenía parámetros para su constructor.

Respuesta

3

Depende si sólo va a tener un solo tipo de bala ...

Si sólo uno, entonces yo diría que estaría bien.

Pero si tiene una bala , DoubleBullet, PowerBullet, NukeBullet, etc.

Entonces me gustaría hacer clase base de la bala y todos los demás derrived de ella

Entonces me haría fábrica de bala y tendría CreateBullet, CreatePowerBullet, etc.

La otra pregunta es, ¿hará algo más una bala? Si es así, me gustaría crear una fábrica de consolidar la lógica de la creación en un solo lugar ...

De lo contrario huele a su uso de DI simplemente estar usando DI ...

+0

Además, si "bala" en sí misma era un objeto muy complejo con su propio árbol de objetos, probablemente querrá una fábrica para evitar que Ship tenga dependencias a las dependencias de Bullet. – Epaga

1

La inyección de dependencia no es adecuada para este caso. Si crea una fábrica para esto, usará en exceso patrones de diseño. No puedes desacoplar todo el sistema, en este caso Ship tiene una composición con Bullet, y en caso de que necesites algo más complejo que ese otro patrón (no necesariamente DI) podría ser adecuado.

+1

Entonces, ¿solo usa DI para objetos de tipo de servicio y singletons? –

1

Sí, esto huele a sobre-architecting . Sin embargo, fuera de mi cabeza, podrías tener una propiedad que almacenara el tipo de viñeta y luego tu marco DI (ninject aquí) creara la viñeta.

public Type BulletType {get; set;} 

public void fire() 
{ 
    var b = (BulletType) kernel.get(BulletType); 
    b.fire(point, direction); 
} 
+0

Entonces kernel.get (BulletType) buscará el nombre de clase que he especificado externamente y me creará una instancia de eso? ¿Significa esto que el punto y la dirección no se pueden pasar en el constructor, sino que tienen que establecerse después de la creación? –

+0

Sí, kernel hace la búsqueda y la creación en el Marco Ninject. Y no toma parámetros como el punto. ¿Es eso un problema? – Ray

2

Ya casi lo tienes. Si desea desacoplarse con la clase Bullet, entonces, en mi opinión, la mejor solución es inyectar una fábrica que pueda crear objetos Bullet.

Tenga en cuenta que tiene varios niveles de indirección que puede tomar, cada uno le brinda más flexibilidad, pero requiere más código y posiblemente sea más difícil de entender. Lo más simple es tener BulletFactory y Bullet ambos sean tipos concretos. Esto significa que no puede tener fácilmente implementaciones diferentes de ellos, pero aún puede extenderlos y pasar una subclase de BulletFactory que devuelve las subclases de Bullet. Si su único propósito para la inyección es facilitar las pruebas unitarias, esta es la ruta que tomaría. Por supuesto, también puede hacer que BulletFactory sea una interfaz, o Bullet una interfaz, o ambas. Si va a tener implementos diferentes para fines que no sean de prueba, esta es la ruta que tomaría.

Finalmente, debe decidir si los beneficios de desacoplamiento de la clase Bullet de su clase PlayerShip valen la pena. El acoplamiento cerrado no es malo y no debe evitarse a toda costa — tiene sentido en algunos contextos, y no en otros. Solo la experiencia te ayudará a decidir cuándo juntar las clases y cuándo desacoplarlas.