Inyección de dependencia versus patrón de fábrica


498

La mayoría de los ejemplos citados para el uso de la inyección de dependencia, también podemos resolverlos usando el patrón de fábrica. Parece que cuando se trata de uso / diseño, la diferencia entre la inyección de dependencia y la fábrica es borrosa o delgada.

¡Una vez que alguien me dijo que es cómo lo usas lo que hace la diferencia!

Una vez utilicé un contenedor DI de StructureMap para resolver un problema, más tarde lo rediseñé para trabajar con una fábrica simple y eliminé referencias a StructureMap.

¿Alguien puede decirme cuál es la diferencia entre ellos y dónde usar qué, cuál es la mejor práctica aquí?


22
¿No pueden estos dos enfoques complementarse entre sí: usar la inyección de dependencia para inyectar clases de fábrica?
Richard Ev

20
¡Sería realmente bueno si esta pregunta tuviera una respuesta con algún código! ¿Todavía no veo cómo DI sería beneficioso / diferente de usar una fábrica para la creación? ¿Solo necesitará reemplazar esa línea en la clase de fábrica para cambiar qué obj / implementación se crea?
Gideon

2
@Gideon, ¿no te obligaría a compilar tu aplicación, o al menos el módulo que contiene la clase de fábrica?
ácido lisérgico

1
@liortal sí, eso es correcto. Hice un largo estudio sobre DI desde ese comentario y ahora entiendo que la DI lleva el método de fábrica un paso adelante.
gideon

1
Mira esta gran respuesta: stackoverflow.com/questions/4985455/… : lo expresa muy bien y proporciona ejemplos de código.
Luis Pérez

Respuestas:


294

Cuando utiliza una fábrica, su código sigue siendo responsable de crear objetos. Por DI, externaliza esa responsabilidad a otra clase o marco, que es independiente de su código.


172
El patrón DI no requiere ningún marco. Puede hacer DI escribiendo manualmente las fábricas que hacen DI. Los marcos DI simplemente lo hacen más fácil.
Esko Luontola

28
@Perpetualcoder - Gracias @Esko - No te quedes atrapado en el marco de palabras que significa una biblioteca avanzada de terceros.
willcodejavaforfood

44
+1 @willcode gracias! Por lo tanto, debe cambiar los archivos config / xml en su lugar. Veo. El enlace wiki en.wikipedia.org/wiki/… define el patrón de fábrica comoManually-Injected Dependency
gideon

55
No tengo la ventaja de cambiar 1 línea de XML frente a cambiar 1 línea de código. ¿Podrías dar más detalles?
Rafael Eyng

1
Repita la respuesta OP reemplazando "DI" con "fábrica", todavía tiene sentido.
Edson Medina

219

Sugeriría mantener los conceptos claros y simples. La inyección de dependencias es más un patrón arquitectónico para acoplar componentes de software sin apretar. El patrón de fábrica es solo una forma de separar la responsabilidad de crear objetos de otras clases en otra entidad. El patrón de fábrica se puede llamar como una herramienta para implementar DI. La inyección de dependencia se puede implementar de muchas maneras, como DI utilizando constructores, utilizando archivos xml de mapeo, etc.


44
Es cierto que Factory Pattern es una de las formas de implementar la inyección de dependencia. Otro beneficio al usar la inyección de dependencia contra el patrón de fábrica es que DI Frameworks le daría flexibilidad de cómo registrar sus abstracciones contra sus tipos concretos. Tales como Código como Config, XML o Auto Configuration. Esa flexibilidad le permitirá administrar la vida útil de sus objetos o decidir cómo y cuándo registrar sus interfaces.
Teoman shipahi

1
El patrón de fábrica ofrece abstracción de mayor nivel que DI. Una fábrica puede ofrecer opciones de configuración al igual que DI, pero también puede optar por ocultar todos esos detalles de configuración, de modo que la fábrica pueda decidir cambiar a una implementación completamente diferente sin que el cliente lo sepa. DI por sí solo no permite esto. DI requiere que el cliente especifique los cambios que desea.
neurona

1
Buena respuesta. Muchos se confunden con esa pregunta: "¿Qué patrones debo elegir?" De hecho, los patrones de diseño son solo una forma de resolver problemas en situaciones adecuadas. Si no sabe qué patrón de diseño debe usar, o "¿Dónde debo implementar el patrón?" entonces no necesitas eso en este momento.
Benyi

2
Creo que es más exacto decir que Factory Pattern es una herramienta para implementar IoC (no DI). Tenga en cuenta que DI es una forma de IoC
Hooman Bahreini

185

Inyección de dependencia

En lugar de crear una instancia de las partes en sí, un automóvil solicita las partes que necesita para funcionar.

class Car
{
    private Engine engine;
    private SteeringWheel wheel;
    private Tires tires;

    public Car(Engine engine, SteeringWheel wheel, Tires tires)
    {
        this.engine = engine;
        this.wheel = wheel;
        this.tires = tires;
    }
}

Fábrica

Coloca las piezas juntas para hacer un objeto completo y oculta el tipo de concreto de la persona que llama.

static class CarFactory
{
    public ICar BuildCar()
    {
        Engine engine = new Engine();
        SteeringWheel steeringWheel = new SteeringWheel();
        Tires tires = new Tires();
        ICar car = new RaceCar(engine, steeringWheel, tires);
        return car;
    }   
}

Resultado

Como puede ver, las fábricas y DI se complementan entre sí.

static void Main()
{
     ICar car = CarFactory.BuildCar();
     // use car
}

¿Te acuerdas de Ricitos de oro y los tres osos? Bueno, la inyección de dependencia es algo así. Aquí hay tres formas de hacer lo mismo.

void RaceCar() // example #1
{
    ICar car = CarFactory.BuildCar();
    car.Race();
}

void RaceCar(ICarFactory carFactory) // example #2
{
    ICar car = carFactory.BuildCar();
    car.Race();
}

void RaceCar(ICar car) // example #3
{
    car.Race();
}

Ejemplo # 1 - Esto es lo peor porque oculta completamente la dependencia. Si miraras el método como una caja negra, no tendrías idea de que requería un automóvil.

Ejemplo # 2 - Esto es un poco mejor porque ahora sabemos que necesitamos un automóvil ya que pasamos en una fábrica de automóviles. Pero esta vez estamos pasando demasiado, ya que todo lo que el método realmente necesita es un automóvil. Estamos pasando en una fábrica solo para construir el automóvil cuando el automóvil podría construirse fuera del método y pasarlo.

Ejemplo # 3 - Esto es ideal porque el método pide exactamente lo que necesita. No demasiado o muy poco. No tengo que escribir un MockCarFactory solo para crear MockCars, puedo pasar el simulacro directamente. Es directo y la interfaz no miente.

Este Google Tech Talk de Misko Hevery es sorprendente y es la base de lo que deriva mi ejemplo. http://www.youtube.com/watch?v=XcT4yYu_TTs


1
El patrón de fábrica se inyecta como DI.
Mangesh Pimpalkar

77
@PhilGoetz Lo que está describiendo suena más como el patrón del Localizador de servicios. Tienen objetivos similares, ya que su objetivo es desacoplar los servicios de sus consumidores. Sin embargo, existen muchas desventajas en el patrón del Localizador de servicios. Principalmente, ocultar dependencias no es algo bueno. El consumidor aún necesita obtener sus dependencias, pero en lugar de definir una interfaz clara, se pasan 'en secreto' y se basan en el estado global. En el ejemplo, el consumidor no tiene idea de la fábrica, solo pregunta qué necesita y no tiene que preocuparse por cómo se construye esa necesidad.
Despertar

1
@MatthewWhited La mayoría de las decisiones de diseño tienen un compromiso. Con DI, obtienes flexibilidad, transparencia y un sistema más comprobable, pero a costa de exponer tus agallas. Muchas personas consideran que esto es una compensación aceptable. Esto no quiere decir que DI sea siempre la mejor solución y esta pregunta no se trata de eso. El ejemplo pretende mostrar la diferencia entre DI y el patrón de fábrica mostrando algunos usos buenos y malos de cada uno.
Despertar el

3
Este no es un patrón DI, es solo una implementación de IoC. DI usa un ServiceLocator para determinar la dependencia correcta e inyectarla en el constructor durante la creación del objeto, su código solo segrega la creación de objetos del alcance de su clase.
Diego Mendes

3
@DiegoMendes Lo que está describiendo es un marco que automatiza la DI. El ServiceLocator como lo llama hace el DI por usted. Lo que estoy mostrando es el patrón en sí mismo que no requiere ningún marco sofisticado. Consulte stackoverflow.com/a/140655/1160036 , o consulte en.wikipedia.org/wiki/… : "[lista de marcos] admite la inyección de dependencia, pero no es necesario que realice la inyección de dependencia". Además, "Una inyección es el paso de una dependencia a un objeto dependiente". Has terminado de complicar un concepto maravillosamente simple.
Despertar

50

La razón por la que la inyección de dependencia (DI) y los patrones de fábrica son similares es porque son dos implementaciones de Inversión de control (IoC), que es una arquitectura de software. En pocas palabras, son dos soluciones al mismo problema.

Entonces, para responder a la pregunta, la principal diferencia entre el patrón Factory y DI es cómo se obtiene la referencia del objeto. Con la inyección de dependencia como su nombre lo indica, la referencia se inyecta o se le da a su código. Con el patrón Factory, su código debe solicitar la referencia para que su código recupere el objeto. Ambas implementaciones eliminan o desacoplan el enlace entre el código y la clase o tipo subyacente de la referencia de objeto que utiliza el código.

Vale la pena señalar que los patrones Factory (o de hecho patrones Abstract Factory que son fábricas que devuelven nuevas fábricas que devuelven referencias de objeto) se pueden escribir para elegir dinámicamente o vincular el tipo o clase de objeto que se solicita en tiempo de ejecución. Esto los hace muy similares (incluso más que DI) al patrón del Localizador de servicios, que es otra implementación de IoC.

El patrón de diseño de Factory es bastante antiguo (en términos de software) y ha existido por un tiempo. Desde la reciente popularidad del patrón arquitectónico IoC, está teniendo un resurgimiento.

Supongo que cuando se trata de patrones de diseño de IoC: los inyectores deben inyectarse, los localizadores deben ubicarse y las fábricas han sido refactorizadas.


3
Esta es la mejor respuesta ... otras respuestas o no mencionan IoC o no reconocen que DI es una forma de IoC.
Hooman Bahreini

Gracias, cuando estudié por primera vez el COI, casi grité que esta era solo otra forma del patrón de fábrica, resulta que son muy similares entre sí
Harvey Lin

40

Hay problemas que son fáciles de resolver con la inyección de dependencia que no se resuelven tan fácilmente con un conjunto de fábricas.

Algunas de las diferencias entre, por un lado, la inversión de control y la inyección de dependencia (IOC / DI), y, por otro lado, un localizador de servicios o un conjunto de fábricas (fábrica), es:

IOC / DI es un ecosistema completo de objetos de dominio y servicios en sí mismo. Configura todo para usted en la forma que especifique. Sus objetos y servicios de dominio son construidos por el contenedor, y no se construyen ellos mismos: por lo tanto, no tienen ninguna dependencia en el contenedor o en ninguna fábrica. IOC / DI permite un grado extremadamente alto de configurabilidad, con toda la configuración en un solo lugar (construcción del contenedor) en la capa superior de su aplicación (la GUI, el front-end web).

Factory extrae parte de la construcción de sus objetos y servicios de dominio. Pero los objetos y servicios de dominio siguen siendo responsables de descubrir cómo construirse y cómo obtener todas las cosas de las que dependen. Todas estas dependencias "activas" se filtran a través de todas las capas de su aplicación. No hay un solo lugar para configurar todo.


26

Una desventaja de DI es que no puede inicializar objetos con lógica. Por ejemplo, cuando necesito crear un personaje que tenga nombre y edad aleatorios, DI no es la opción sobre el patrón de fábrica. Con las fábricas, podemos encapsular fácilmente el algoritmo aleatorio de la creación de objetos, que admite uno de los patrones de diseño llamado "Encapsular lo que varía".


22

La gestión del ciclo de vida es una de las responsabilidades que los contenedores de dependencia asumen además de la creación de instancias y la inyección. El hecho de que el contenedor a veces mantenga una referencia a los componentes después de la creación de instancias es la razón por la que se llama un "contenedor", y no una fábrica. Los recipientes de inyección de dependencia generalmente solo guardan una referencia a los objetos que necesita para administrar los ciclos de vida, o que se reutilizan para futuras inyecciones, como singletons o flyweights. Cuando se configura para crear nuevas instancias de algunos componentes para cada llamada al contenedor, el contenedor generalmente solo se olvida del objeto creado.

De: http://tutorials.jenkov.com/dependency-injection/dependency-injection-containers.html


15

Creo que DI es un tipo de capa de abstracción en las fábricas, pero también proporcionan beneficios más allá de la abstracción. Una verdadera fábrica sabe cómo instanciar un solo tipo y configurarlo. Una buena capa DI proporciona la capacidad, a través de la configuración, de crear instancias y configurar muchos tipos.

Obviamente, para un proyecto con unos pocos tipos simples que requiere una lógica empresarial relativamente estable en su construcción, el patrón de fábrica es simple de entender, implementar y funciona bien.

OTOH, si tiene un proyecto que contiene numerosos tipos cuyas implementaciones espera cambiar con frecuencia, DI le brinda la flexibilidad a través de su configuración para hacerlo en tiempo de ejecución sin tener que recompilar sus fábricas.


14

Teoría

Hay dos puntos importantes a considerar:

  1. Quien crea objetos

    • [Fábrica]: debe escribir CÓMO se debe crear el objeto. Tiene una clase Factory separada que contiene lógica de creación.
    • [Inyección de dependencia]: en casos prácticos se realizan mediante marcos externos (por ejemplo, en Java, que sería spring / ejb / guice). La inyección ocurre "mágicamente" sin la creación explícita de nuevos objetos.
  2. Qué tipo de objetos maneja:

    • [Fábrica]: generalmente responsable de la creación de objetos con estado
    • [Inyecciones de dependencia] Más probabilidades de crear objetos sin estado

Ejemplo práctico de cómo usar la inyección de fábrica y de dependencia en un solo proyecto

  1. Lo que queremos construir

Módulo de aplicación para crear orden que contiene múltiples entradas llamadas línea de orden.

  1. Arquitectura

Supongamos que queremos crear la siguiente arquitectura de capa:

ingrese la descripción de la imagen aquí

Los objetos de dominio pueden ser objetos almacenados dentro de la base de datos. El repositorio (DAO) ayuda a recuperar objetos de la base de datos. El servicio proporciona API a otros módulos. Permite operaciones en el ordermódulo

  1. Capa de dominio y uso de fábricas

Las entidades que estarán en la base de datos son Order y OrderLine. El pedido puede tener varias líneas de pedido. Relación entre Order y OrderLine

Ahora viene una parte importante del diseño. ¿Deberían los módulos externos a este crear y administrar OrderLines por su cuenta? No. La línea de pedido debe existir solo cuando tiene un pedido asociado. Sería mejor si pudiera ocultar la implementación interna a clases externas.

Pero, ¿cómo crear un pedido sin conocer las líneas de pedido?

Fábrica

Alguien que quiere crear un nuevo pedido usó OrderFactory (que ocultará detalles sobre el hecho de cómo creamos un pedido).

ingrese la descripción de la imagen aquí

Así se verá dentro de IDE. Se domainusarán clases fuera del paquete en OrderFactorylugar del constructor dentroOrder

  1. Inyección de dependencia La inyección de dependencia se usa más comúnmente con capas sin estado, como repositorio y servicio.

OrderRepository y OrderService son administrados por el marco de inyección de dependencias. El repositorio es responsable de administrar las operaciones CRUD en la base de datos. El servicio inyecta el Repositorio y lo usa para guardar / encontrar las clases de dominio correctas.

ingrese la descripción de la imagen aquí


¿Puedes por favor aclarar esto? [Factory]: Usually responsible for creation of stateful objects [Dependency Injections] More likely to create stateless objectsNo entiendo por qué
Maksim Dmitriev

2
Es probable que los objetos con estado estén en la capa de dominio de la aplicación donde asigna sus datos a la base de datos, por lo general, no usa la inyección de dependencia allí. Factory se usa a menudo para crear AggregateRoot a partir de un árbol de objetos complicados
Marcin Szymczak

12

Sé que esta pregunta es antigua pero me gustaría agregar mis cinco centavos,

Creo que la inyección de dependencia (DI) es en muchos sentidos como un patrón de fábrica configurable (FP), y en ese sentido cualquier cosa que pueda hacer con DI podrá hacerlo con dicha fábrica.

En realidad, si usa spring por ejemplo, tiene la opción de autoabastecer recursos (DI) o hacer algo como esto:

MyBean mb = ctx.getBean("myBean");

Y luego usa esa instancia 'mb' para hacer cualquier cosa. ¿No es una llamada a una fábrica que te devolverá una instancia?

La única diferencia real que noto entre la mayoría de los ejemplos de FP es que puede configurar lo que es "myBean" en un xml o en otra clase, y un marco funcionará como la fábrica, pero aparte de eso es lo mismo, y usted puede tener una fábrica que lea un archivo de configuración u obtenga la implementación según lo necesite.

Y si me preguntas mi opinión (y sé que no lo hiciste), creo que DI hace lo mismo pero solo agrega más complejidad al desarrollo, ¿por qué?

bueno, para empezar, para saber cuál es la implementación que se está utilizando para cualquier bean que conecte automáticamente con DI, debe ir a la configuración misma.

pero ... ¿qué pasa con la promesa de que no tendrá que conocer la implementación del objeto que está utilizando? ¡No! ¿seriamente? cuando usas un enfoque como este ... ¿no eres el mismo que escribe la implementación? e incluso si no lo haces, ¿no estás mirando casi todo el tiempo cómo la implementación hace lo que se supone que debe hacer?

y por último, no importa cuánto te promete un marco DI que construirás cosas desacopladas de él, sin dependencias de sus clases, si estás usando un marco construyes todo en él, si es necesario cambiar el enfoque o el marco no será una tarea fácil ... ¡NUNCA!... pero, dado que construye todo en torno a ese marco en particular en lugar de preocuparse por cuál es la mejor solución para su negocio, se enfrentará a un gran problema al hacerlo.

De hecho, la única aplicación comercial real para un enfoque de FP o DI que puedo ver es si necesita cambiar las implementaciones que se utilizan en tiempo de ejecución , pero al menos los marcos que conozco no le permiten hacer eso, debe irse todo perfecto en la configuración en el momento del desarrollo y si necesita que use otro enfoque.

Entonces, si tengo una clase que funciona de manera diferente en dos ámbitos en la misma aplicación (digamos, dos compañías de una explotación), tengo que configurar el marco para crear dos beans diferentes y adaptar mi código para usar cada uno. ¿No es lo mismo que si simplemente escribiera algo como esto:

MyBean mb = MyBeanForEntreprise1(); //In the classes of the first enterprise
MyBean mb = MyBeanForEntreprise2(); //In the classes of the second enterprise

lo mismo que esto:

@Autowired MyBean mbForEnterprise1; //In the classes of the first enterprise
@Autowired MyBean mbForEnterprise2; //In the classes of the second enterprise

Y esto:

MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise1"); //In the classes of the first enterprise
MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise2"); //In the classes of the second enterprise

En cualquier caso, tendrá que cambiar algo en su aplicación, ya sean clases o archivos de configuración, pero deberá hacerlo y volver a implementarlo.

¿No sería bueno hacer algo como esto?

MyBean mb = (MyBean)MyFactory.get("mb"); 

¿Y de esa manera, configura el código de la fábrica para obtener la implementación correcta en tiempo de ejecución dependiendo de la empresa de usuario registrada? Ahora eso sería útil. Simplemente puede agregar un nuevo jar con las nuevas clases y establecer las reglas, incluso incluso en tiempo de ejecución (o agregar un nuevo archivo de configuración si deja abierta esta opción), sin cambios en las clases existentes. ¡Esta sería una fábrica dinámica!

¿No sería más útil que tener que escribir dos configuraciones para cada empresa, y tal vez incluso tener dos aplicaciones diferentes para cada uno?

Puede decirme que no necesito hacer el cambio en tiempo de ejecución, por lo que configuro la aplicación y, si heredo la clase o uso otra implementación, simplemente cambio la configuración y la vuelvo a implementar. Ok, eso también se puede hacer con una fábrica. Y se honesto, ¿cuántas veces haces esto? tal vez solo cuando tenga una aplicación que se utilizará en otro lugar de su empresa, y vaya a pasar el código a otro equipo, y ellos harán cosas como esta. Pero bueno, eso también se puede hacer con la fábrica, ¡y sería aún mejor con una fábrica dinámica!

De todos modos, la sección de comentarios está abierta para que me mates.


3
Demasiados desarrolladores piensan que los marcos de inyección de dependencia se crean para aportar algo nuevo. Como bien explica, las fábricas tradicionales (a menudo fábrica abstracta) pueden desempeñar el mismo papel de inversión de dependencia. ¿Inversión vs inyección? Para mí, el único "beneficio" del marco de inyección de dependencias es que no tenemos que cambiar / recompilar el código (ya que la mayoría de las veces se puede configurar con XML como Spring) cuando se agrega / cambia una dependencia. ¿Por qué evitar recompilar? Para evitar algunos posibles errores humanos al cambiar la dependencia / fábrica. Pero con nuestros excelentes IDEs, la refactorización funciona bien :)
Mik378

6

El COI es un concepto que se implementa de dos maneras. La creación de dependencias y la inyección de dependencias, Factory / Abstract factory son el ejemplo de creación de dependencias. La inyección de dependencia es constructor, configurador e interfaz. El núcleo del COI es no depender de las clases concretas, sino definir el resumen de métodos (por ejemplo, una interfaz / clase abstracta) y usar ese resumen para llamar al método de clase concreta. Al igual que el patrón Factory, devuelve la clase base o la interfaz. De manera similar, la inyección de dependencia utiliza la clase / interfaz base para establecer el valor de los objetos.


4

Con la inyección de dependencias, el cliente no necesita obtener sus dependencias por sí solo, todo está preparado de antemano.

Con las fábricas, alguien tiene que llamar a esos para llevar los objetos generados al lugar donde se necesitan.

La diferencia radica principalmente en esta línea donde se realiza la llamada a la fábrica y la búsqueda del objeto construido.

Pero con las fábricas tienes que escribir esta 1 línea en todas partes donde necesites un objeto así. Con DI solo tiene que crear el cableado (relación entre el uso y el objeto creado) una vez y confiar en la presencia del objeto después en todas partes. Por otro lado, la DI a menudo requiere un poco más de trabajo (cuánto depende del marco) en el lado de la preparación.


3

Tuve la misma pregunta tan pronto como leí sobre DI y terminé en esta publicación. Finalmente, esto es lo que entendí, pero corrígeme si estoy equivocado.

"Hace mucho tiempo había pequeños reinos con sus propios órganos de gobierno controlando y tomando decisiones basadas en sus propias reglas escritas. Más tarde se formó un gran gobierno que eliminó a todos estos pequeños órganos de gobierno que tienen un conjunto de reglas (constitución) y se implementan a través de los tribunales".

Los órganos rectores de los pequeños reinos son "fábricas"

El gran gobierno es el "Inyector de dependencia".


1
Entonces, ¿CUÁNDO uno considera que un pequeño gobierno anterior ahora es grande? ¿En qué medida?
Prisionero CERO

3

Puede echar un vistazo a este enlace para ver una comparación de los dos enfoques (y otros) en un ejemplo real.

Básicamente, cuando los requisitos cambian, terminas modificando más código si usas fábricas en lugar de DI.

Esto también es válido con DI manual (es decir, cuando no hay un marco externo que proporcione las dependencias a sus objetos, pero las pasa en cada constructor).


3

La mayoría de las respuestas aquí explican la diferencia conceptual y los detalles de implementación de ambos. Sin embargo, no pude encontrar una explicación sobre la diferencia en la aplicación, que es la OMI más importante y sobre la que OP preguntó. Así que déjame volver a abrir este tema ...

¡Una vez que alguien me dijo que es cómo lo usas lo que hace la diferencia!

Exactamente. En el 90% de los casos, puede obtener referencias de objetos utilizando Factory o DI y, por lo general, termina con este último. En otro 10% de los casos, usar Factory es la forma correcta . Estos casos incluyen la obtención de objetos por variable en los parámetros de tiempo de ejecución. Me gusta esto:

IWebClient client = factoryWithCache.GetWebClient(url: "stackoverflow.com",
        useCookies: false, connectionTimeout: 120);

En este caso, clientno es posible obtener DI (o al menos requiere una solución fea). Por lo tanto, como regla general para tomar una decisión: si se puede obtener una dependencia sin ningún parámetro calculado en tiempo de ejecución, entonces se prefiere DI; de lo contrario, use Factory.


2

Creo que DI es una forma de configurar o instanciar un bean. El DI se puede hacer de muchas maneras, como constructor, setter-getter, etc.

El patrón de fábrica es solo otra forma de instanciar frijoles. este patrón se usará principalmente cuando tenga que crear objetos usando el patrón de diseño de fábrica, porque mientras usa este patrón no configura las propiedades de un bean, solo crea una instancia del objeto.

Consulte este enlace: Inyección de dependencias


2

Binoj

No creo que tengas que elegir uno sobre el otro.

El acto de mover una clase o interfaz dependiente a un constructor o setter de clase sigue el patrón DI. El objeto que pasa al constructor o conjunto se puede implementar con Factory.

¿Cuándo usar? Use el patrón o patrones que se encuentran en su timonera de desarrollador. ¿Con qué se sienten más cómodos y les resulta más fácil de entender?


2

Creo que 3 aspectos importantes rigen los objetos y su uso:
1. Creación de instancias (de una clase junto con la inicialización, si corresponde).
2. Inyección (de la instancia así creada) donde se requiere.
3. Gestión del ciclo de vida (de la instancia así creada).

Usando el patrón Factory, se logra el primer aspecto (instanciación) pero los dos restantes son cuestionables. La clase que usa otras instancias debe codificar las fábricas (en lugar de crear instancias), lo que dificulta la capacidad de acoplamiento. Además, la gestión del ciclo de vida. de instancias en un desafío en una aplicación grande donde una fábrica se usa en varios lugares (particularmente, si la fábrica no gestiona el ciclo de vida de la instancia que regresa, se vuelve fea) .

Usando un DI (del patrón IoC) por otro lado, los 3 se abstraen fuera del código (al contenedor DI) y el bean administrado no necesita nada sobre esta complejidad. Acoplamiento suelto , un objetivo arquitectónico muy importante se puede lograr tranquilamente cómodamente. Otro objetivo arquitectónico importante, la separación de las preocupaciones se puede lograr mucho mejor que las fábricas.

Mientras que las fábricas pueden ser adecuadas para aplicaciones pequeñas, las grandes serían mejores para elegir DI que las fábricas.


1

Mis pensamientos:

Inyección de dependencia: pase a los colaboradores como parámetros a los constructores. Dependency Injection Framework: una fábrica genérica y configurable para crear los objetos para pasar como parámetros a los constructores.


1
Sí exactamente. Casi todas las menciones de Dependency Injection (DI) en estas preguntas y respuestas usan mal el término en contraste con esta definición. Un contenedor de inyección de dependencia (DIC) es el marco más común que actúa como una fábrica genérica y configurable para crear objetos.
CXJ

1

Un marco de inyección es una implementación del patrón de fábrica.

Todo depende de tus requerimientos. Si necesita implementar el patrón de fábrica en una aplicación, es muy probable que una de las innumerables implementaciones de marcos de inyección cumpla con sus requisitos.

Solo debe implementar su propia solución si ninguno de los marcos de terceros cumple con sus requisitos. Cuanto más código escriba, más código deberá mantener. El código es un pasivo, no un activo.

Los argumentos sobre qué implementación debe utilizar no son tan importantes como comprender las necesidades arquitectónicas de su aplicación.


1

Patrón de diseño de fábrica

El patrón de diseño de fábrica se caracteriza por

  • Una interfaz
  • Clases de implementación
  • Una fábrica

Puedes observar algunas cosas cuando te preguntas a ti mismo como a continuación

  • ¿Cuándo creará la fábrica un objeto para las clases de implementación: tiempo de ejecución o tiempo de compilación?
  • ¿Qué sucede si desea cambiar la implementación en tiempo de ejecución? - No es posible

Estos se manejan mediante inyección de dependencia.

Inyección de dependencia

Puede tener diferentes formas de inyectar dependencia. Para simplificar, vamos con la inyección de interfaz

En DI, el contenedor crea las instancias necesarias y las "inyecta" en el objeto.

Por lo tanto, elimina la instanciación estática.

Ejemplo:

public class MyClass{

  MyInterface find= null;

  //Constructor- During the object instantiation

  public MyClass(MyInterface myInterface ) {

       find = myInterface ;
  }

  public void myMethod(){

       find.doSomething();

  }
}

1

Por su valor nominal se ven iguales

En términos muy simples, Factory Pattern, un patrón de creación, nos ayuda a crear un objeto: "Definir una interfaz para crear un objeto". Si tenemos un tipo de valor de clave de grupo de objetos (por ejemplo, Diccionario), pasando la clave a la Fábrica (me refiero al Patrón de Fábrica Simple) puede resolver el Tipo. ¡Trabajo hecho! El Marco de inyección de dependencias (como Mapa de estructura, Ninject, Unidad ... etc.) por otro lado parece estar haciendo lo mismo.

Pero ... "No reinventes la rueda"

Desde una perspectiva arquitectónica, es una capa de unión y "No reinventes la rueda".

Para una aplicación de grado empresarial, el concepto de DI es más una capa arquitectónica que define dependencias. Para simplificar esto aún más, puede pensar en esto como un proyecto de biblioteca de clases separado, que resuelve la dependencia. La aplicación principal depende de este proyecto donde el solucionador de dependencias se refiere a otras implementaciones concretas y a la resolución de dependencias.

Además de "GetType / Create" de una Fábrica, la mayoría de las veces necesitamos más funciones (capacidad de usar XML para definir dependencias, burlas y pruebas unitarias, etc.). Como se refirió al Mapa de estructura, mire la lista de características del Mapa de estructura . Es claramente más que simplemente resolver el mapeo simple de objetos. ¡No reinventes la rueda!

Si todo lo que tienes es un martillo, todo parece un clavo

Dependiendo de sus requisitos y del tipo de aplicación que cree, debe elegir. Si tiene pocos proyectos (puede ser uno o dos ...) e involucra pocas dependencias, puede elegir un enfoque más simple. Es como usar el acceso a datos ADO .Net sobre el uso de Entity Framework para una simple base de datos de 1 o 2 llamadas, donde introducir EF es una exageración en ese escenario.

Pero para un proyecto más grande o si su proyecto se hace más grande, recomendaría encarecidamente tener una capa DI con un marco y hacer espacio para cambiar el marco DI que usa (Use una fachada en la aplicación principal (aplicación web, API web, escritorio ..etc.).


1

Con una fábrica, puede agrupar interfaces relacionadas, por lo tanto, si los parámetros pasados ​​se pueden agrupar en una fábrica, también es una buena solución para constructor overinjectionver este código *):

public AddressModelFactory(IAddressAttributeService addressAttributeService,
        IAddressAttributeParser addressAttributeParser,
        ILocalizationService localizationService,
        IStateProvinceService stateProvinceService,
        IAddressAttributeFormatter addressAttributeFormatter)
    {
        this._addressAttributeService = addressAttributeService;
        this._addressAttributeParser = addressAttributeParser;
        this._localizationService = localizationService;
        this._stateProvinceService = stateProvinceService;
        this._addressAttributeFormatter = addressAttributeFormatter;
    }

Mira el constructor, solo tienes que pasar IAddressModelFactoryallí, por lo que menos parámetros *):

 public CustomerController(IAddressModelFactory addressModelFactory,
        ICustomerModelFactory customerModelFactory,
        IAuthenticationService authenticationService,
        DateTimeSettings dateTimeSettings,
        TaxSettings taxSettings,
        ILocalizationService localizationService,
        IWorkContext workContext,
        IStoreContext storeContext,
        ICustomerService customerService,
        ICustomerAttributeParser customerAttributeParser,
        ICustomerAttributeService customerAttributeService,
        IGenericAttributeService genericAttributeService,
        ICustomerRegistrationService customerRegistrationService,
        ITaxService taxService,
        CustomerSettings customerSettings,
        AddressSettings addressSettings,...

Usted ve en CustomerControllermuchos parámetros pasados, sí, puede ver esto, constructor overinjectionpero así es como funciona DI. Y no hay nada malo con elCustomerController .

*) El código es de nopCommerce.


1

En términos simples, el método de Inyección de Dependencias vs Fábrica implica un mecanismo de empuje contra tirón, respectivamente.

Mecanismo de extracción : la clase depende indirectamente del Método de fábrica, que a su vez depende de clases concretas.

Mecanismo de empuje : el componente raíz se puede configurar con todos los componentes dependientes en una sola ubicación y, por lo tanto, promueve un alto mantenimiento y un acoplamiento flojo.

Con el método Factory, la responsabilidad aún recae en la clase (aunque indirectamente) para crear un nuevo objeto donde, como con la inyección de dependencia, esa responsabilidad se subcontrata (a costa de la abstracción que se filtra)


0

Creo que estos son ortogonales y se pueden usar juntos. Déjame mostrarte un ejemplo que encontré recientemente en el trabajo:

Estábamos usando el framework Spring en Java para DI. Una clase singleton ( Parent) tuvo que instanciar nuevos objetos de otra clase ( Child), y esos tenían colaboradores complejos:

@Component
class Parent {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
    }

    void method(int p) {
        Child c = new Child(dep1, dep2, ..., depN, p);
        // ...
    }
}

En este ejemplo, Parenttiene que recibir DepXinstancias solo para pasarlas al Childconstructor. Problemas con esto:

  1. Parenttiene más conocimiento del Childque debería
  2. Parent tiene más colaboradores de los que debería
  3. Agregar dependencias a Childimplica cambiarParent

Esto es cuando me di cuenta de Factoryque encajaría perfectamente aquí:

  1. Oculta todo excepto los parámetros verdaderos de la Childclase, como se ve porParent
  2. Encapsula el conocimiento de crear un Child, que se puede centralizar en la configuración DI.

Esta es la Parentclase simplificada y la ChildFactoryclase:

@Component
class Parent {
    // ...
    @Autowired
    Parent(ChildFactory childFactory) {
        this.childFactory = childFactory;
    }

    void method(int p) {
        Child c = childFactory.newChild(p);
        // ...
    }
}

@Component
class ChildFactory {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
        // ...
        this.depN = depN;
    }

    Child newChild(int p) {
        return new Child(dep1, dep2, ..., depN, p);
    }
}

0

Utiliza la inyección de dependencia cuando sabe exactamente qué tipo de objetos necesita en este momento. Si bien en el caso del patrón de fábrica, simplemente delega el proceso de creación de objetos a la fábrica, ya que no tiene claro qué tipo exacto de objetos necesita.


-1

Utilizo ambos para crear una estrategia de Inversión de control con más legibilidad para los desarrolladores que necesitan mantenerla después de mí.

Utilizo una fábrica para crear mis diferentes objetos de capa (negocios, acceso a datos).

ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();

Otro desarrollador verá esto y, al crear un objeto Business Layer, buscará en BusinessFactory e Intellisense le dará al desarrollador todas las Business Layers posibles para crear. No tiene que jugar el juego, busca la interfaz que quiero crear.

Esta estructura ya es Inversión de control. Ya no soy responsable de crear el objeto específico. Pero aún debe garantizar la inyección de dependencia para poder cambiar las cosas fácilmente. Crear su propia inyección de dependencia personalizada es ridículo, por lo que uso Unity. Dentro de CreateCarBusiness () le pido a Unity que resuelva qué clase pertenece a esto y es de por vida.

Entonces, mi código de estructura de inyección de dependencia de fábrica es:

public static class BusinessFactory
{
    public static ICarBusiness CreateCarBusiness()
    {
       return Container.Resolve<ICarBusiness>();
    }
}

Ahora tengo el beneficio de ambos. Mi código también es más legible para otros desarrolladores en cuanto a los alcances de mis objetos que uso, en lugar de la Inyección de dependencia del constructor que simplemente dice que cada objeto está disponible cuando se crea la clase.

Lo uso para cambiar el acceso a los datos de mi base de datos a una capa de acceso a datos codificada personalizada cuando creo pruebas unitarias. No quiero que mis pruebas unitarias se comuniquen con bases de datos, servidores web, servidores de correo electrónico, etc. Necesitan probar mi Business Layer porque ahí es donde está la inteligencia.


-4

En mi opinión, utilizar la inyección de dependencia es mucho mejor si usted: 1. implementa su código en una partición pequeña, porque se maneja bien en el desacoplamiento de un código grande. 2. la capacidad de prueba es uno de los casos en los que se puede usar DI porque puede burlarse fácilmente de los objetos no desacoplados. Con el uso de interfaces puede burlarse y probar fácilmente cada objeto. 3. puede revisar simultáneamente cada parte del programa sin necesidad de codificar la otra parte, ya que está desacoplado libremente.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.