2011-05-23 15 views
23

Aquí hay un ejemplo imaginario genérico hecho para esta publicación. Considere 6 clasesInfierno de dependencia: ¿cómo se pasan las dependencias a objetos profundamente anidados?

TableFactory, TableData, TableCRUD, TableSchema, DBConnect, Logger. 

TableFactory es la clase externa, digamos que tiene un objeto TableData para una tabla DB.

En este TableFactory, no hay llamadas a TableSchema o DBConnect o logger. Me refiero a un ejemplo de objetos internos que no se necesitan en el ámbito exterior.

TableData es una búsqueda interna y opera en los datos, por lo que necesita TableCrud, DBConnect y Logger.

TableCrud contiene TableSchema y necesita DBConnect y Logger.

DbConnect itseld, para hacer las cosas divertidas, necesita un registrador. Mi ejemplo ahora tiene 3 alcances de profundidad.

Mi pregunta es bastante simple, si tiene un objeto de 3 (o más) ámbitos que no son invocados por objetos en el ámbito exterior, ¿cómo se envían esos objetos del alcance exterior al interno sin romper la segregación de interfaz Principio -> TableFactory no debería tener que tratar con DBConnect o Logger que necesitan los objetos internos.

Si se respetan los principios de OOP básicos y se pretende una fácil prueba -> se necesitarían objetos externos que requirieran la inyección de los 5 objetos, y luego se obtendrían los objetos necesarios para avanzar más arriba de la cadena. Y los objetos de ámbito interno a su vez requerirían la inyección de las dependencias de sus objetos internos de 3 ámbitos de profundidad, con captadores para esos también. Esto crea objetos de ámbito externo que requieren muchas dependencias y getters para pasarlos.

¿Hay alguna alternativa a esta metodología para pasar objetos, algo que me perdí en el camino? ¡Por favor comparte! Cualquier enlace/comentario apreciado.

Respuesta

45

Es un concepto erróneo común que las dependencias deben pasar a través del gráfico de objetos. Para resumir el ejemplo Miško Hevery da en Clean Code: Don't look for things, una casa que necesita una puerta, no logra necesita saber acerca de la cerradura de la puerta:

class HouseBuilder 
{ 
    public function buildHouse() 
    { 
     $lock = new Lock; 
     $door = new Door($lock); 
     $house = new House($door); 

     return $house; 
    } 
} 

Como se puede ver, la casa está completamente inconsciente del hecho de que la puerta en él requiere un candado. Es responsabilidad del HouseBuilder crear todas las dependencias requeridas y apilarlas a medida que las necesite. De adentro hacia afuera.

En consecuencia, en su escenario, debe identificar qué objetos deben operar en qué dependencias (cf Law of Demeter). Luego, su Creador debe crear todos los colaboradores y asegurarse de que las dependencias se inyecten en los objetos apropiados.

Véase también How to Think About the “new” Operator with Respect to Unit Testing

+6

+1 amo la forma en que esto se pone, agradable y limpio! – Christian

+1

Gordon -> ¡Rock! ;) Gracias amigo y si alguna vez vienes a Montreal, ¡te debo una cerveza por todas las veces que me has visto! No necesitas el karma de todos modos. – stefgosselin

+0

@stef de nada. No estoy seguro si asistiré a Confoo el próximo año, pero si lo hago, felizmente tomaré una cerveza contigo;) – Gordon

1

Si va a tropezar con la misma pregunta comprobar el artículo de Hervey que golpea el ojo toros

http://misko.hevery.com/2008/10/21/dependency-injection-myth-reference-passing/

En caso de que el artículo se desvanece en el futuro aquí está el extracto

"Cada objeto simplemente conoce los objetos con los que interactúa directamente. No hay referencias de objetos que pasan solo para ubicarlos en el lugar correcto donde están n eeded ".

Entonces, lo que hay que hacer es en lugar de crear un gráfico de objetos anidados profundos con pasar las dependencias de arriba a abajo, ir horizontal y administrar dependencias en otro lugar.

Cuestiones relacionadas