Inyección de dependencia: ¿en qué momento se me permite crear un nuevo objeto?

13

Estoy refactorizando una aplicación PHP , y estoy tratando de hacer que la inyección de dependencia (DI) sea lo más posible.

Siento que tengo una buena comprensión de cómo funciona, y ciertamente puedo ver que mis clases se vuelven mucho más delgadas y robustas.

Estoy refactorizando para poder inyectar una dependencia en lugar de crear un nuevo objeto dentro de la clase, pero en algún momento tendré que crear algunos objetos, es decir, usar la newpalabra clave temida .

El problema con el que me he encontrado ahora es ¿en qué punto puedo realmente crear nuevos objetos? Parece que terminaré en una clase de nivel superior, creando montones de objetos nuevos ya que no hay otro lugar a donde ir. Esto se siente mal.

He leído algunos blogs que usan clases de fábrica para crear todos los objetos, y luego se inyecta la fábrica en otras clases. Luego puede llamar a los métodos de fábrica, y la fábrica crea el nuevo objeto para usted.

¡Mi preocupación por hacer esto es que ahora mis clases de fábrica serán newgratuitas! Supongo que esto puede estar bien, ya que son clases de fábrica, pero ¿hay algunas reglas a seguir cuando se usa un patrón de fábrica y DI, o estoy yendo muy lejos de aquí?

Gaz_Edge
fuente
Recomiendo IoC para servicios y políticas. Para las clases de modelo o de ayuda simplemente usaría new. Por supuesto, hay algunos puntos de entrada donde debe llamar al contenedor de IoC, pero no debería haber muchos. Por lo general, configura el IoC una vez y luego solicita que se resuelva una clase por solicitud. En el caso de MVC, ese es típicamente el controlador.
CodesInChaos
La clase de nivel superior que mencionas es parte de la raíz de composición. Está lejos de estar mal.
Facio Ratio

Respuestas:

12

Después de buscar un poco en Google para esto, parece que (como se mencionó en un comentario anterior) la clase de nivel superior de la que hablaba se llama la raíz de composición .

De hecho, parece ser la solución aceptada para agregar la creación de todos los objetos dentro de esta raíz de composición (o haciendo referencia a un contenedor de IoC desde aquí).

Mi preocupación original con esto era que esta clase de nivel superior terminaría siendo un poco desordenada. Esto es cierto hasta cierto punto, pero las ventajas sopesan las desventajas. Por ejemplo, puedo ver que la legibilidad, la capacidad de prueba y el mantenimiento de todas mis otras clases ha mejorado.

La clase de nivel superior puede ser un poco desordenada, llena de newy, set_property()pero tengo que decir que en realidad prefiero tener todo este código en un lugar, en lugar de estar disperso por todas las otras clases

Otra página útil que trata los éxitos de rendimiento de este método aquí

Gaz_Edge
fuente
1
+1 porque nunca antes había escuchado sobre 'Root de composición'.
c_maker
2

Una clase de Fábrica se habrá newesparcido por todas partes. Estaría creando cualquier objeto que esté solicitando y probablemente las dependencias de ese objeto. Dado que el trabajo de las fábricas es crear una instancia del objeto correcto para usted newen esta clase, no es algo malo.

DI es para que tenga un diseño suelto. Puede realizar cambios en su aplicación cambiando la dependencia que se proporciona a cada objeto. Hacer su aplicación flexible, extensible y fácil de probar.

En el nivel superior, tendrá un código que instanciará un par de fábricas, configurará conexiones a los servicios y enviará una respuesta. Tendrá una buena cantidad de newllamadas estáticas para crear instancias de objetos necesarios para su aplicación. Eso sería donde pertenece.

Schleis
fuente
-2

Mis dos centavos aquí:

Estoy refactorizando una aplicación php y estoy tratando de hacer que la inyección de dependencia sea lo más posible

No indica si está utilizando un marco de inyección de dependencia. Creo que definitivamente deberías. Use algo que le brinde las funciones que necesita: /programming/9348376/guice-like-dependency-injection-frameworks-in-php .

El problema con el que me he encontrado ahora es ¿en qué punto puedo realmente crear nuevos objetos? Parece que terminaré en una clase de nivel superior, creando montones de objetos nuevos ya que no hay otro lugar a donde ir. Esto se siente mal.

Normalmente utiliza la configuración o un punto central para la creación de instancias de los objetos iniciales que componen su aplicación. El contenedor creará los objetos por ti.

Luego accede a objetos (servicios, proveedores, controladores ...) a través del contenedor IoC. Si es necesario, creará un objeto transparente para usted o le dará una referencia a la instancia existente adecuada.

Por supuesto, dentro de su implementación particular de objetos, puede crear instancias de otros objetos en los que no necesita DI (estructuras de datos, tipos personalizados, etc.), pero esa es la programación normal.

He leído algunos blogs que usan clases de fábrica para crear todos los objetos, y luego se inyecta la fábrica en otras clases. Luego puede llamar a los métodos de fábrica, y la fábrica crea el nuevo objeto para usted.

Normalmente, utiliza una Fábrica si desea que el marco IoC cree instancias de algunos objetos IoC a través de sus fábricas (esto es necesario cuando la creación de instancias de un objeto en particular requiere un trabajo adicional). Si simplemente puede crear sus objetos con "new Object ()" y establecer algunas propiedades, no necesariamente quiere usar un patrón Factory.

En otras palabras, diría que el uso de un patrón Factory para una clase o grupo de clases depende de cómo desee modelar esas clases, no de si usa DI (a menos que su implementación DI explícitamente requiera fábricas, lo cual es inusual).

También configura su marco IoC para usar una Fábrica cuando está utilizando una biblioteca de terceros que ya requiere el uso de una Fábrica. En este caso no tiene control sobre esto y necesita decirle a su contenedor de IoC: "oye, cuando solicito una de estas interfaces, debe usar esta fábrica para proporcionarme una instancia apropiada".

¡Mi preocupación por hacer esto ahora es que mis clases de fábrica serán nuevas y gratuitas! Supongo que esto puede estar bien, ya que son clases de fábrica, pero hay algunas reglas a seguir cuando se usa el patrón de fábrica y DI, o estoy yendo muy lejos de aquí.

En este caso, parece que no necesita usar patrones de Fábrica para estos objetos / servicios / controladores / lo que sea, y simplemente puede configurar su IoC para instanciar con "nueva" la clase apropiada e inyectar todo lo demás.

Espero que ayude.

jjmontes
fuente
gracias por la respuesta, pero seguramente el contenedor de IoC es la 'clase de nivel superior' a la que me refería. Si solo puedo crear objetos allí, será un desastre.
Gaz_Edge
44
doing DI manually beats the whole purpose of using an Inversion of Control container- Si con eso te refieres a "... que es centralizar tus dependencias en un archivo de configuración" , tienes razón, porque eso es todo lo que realmente hace un contenedor de IoC. El objetivo real de DI es el desacoplamiento, y puede hacerlo proporcionando sus dependencias en un método constructor. No necesita un marco DI para hacer eso.
Robert Harvey
mmm, no crea objetos, le pide al contenedor IoC (desde cualquier lugar donde lo necesite), o usa la inyección de campo / argumento para que sus clases se inyecten automáticamente las clases apropiadas, creadas siempre por el contenedor IoC.
jjmontes
1
Estoy de acuerdo en que necesita un marco para aplicaciones muy grandes . Muchas aplicaciones no son tan grandes y no se benefician de la complejidad adicional de usar un marco DI.
Robert Harvey
2
No dije que lo fuera. Simplemente dije que no necesita un contenedor DI para hacerlo.
Robert Harvey