dependency-injection - patron - inyeccion de dependencias swift
Inyección de dependencia vs patrón de fábrica (27)
La administración del ciclo de vida es una de las responsabilidades que los contenedores de dependencia asumen además de la creación de instancias e 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 denomina "contenedor", y no una fábrica. Los contenedores de inyección de dependencia por lo general solo mantienen una referencia a los objetos que necesita para administrar los ciclos de vida, o que se reutilizan para inyecciones futuras, como singletons o contrapesos. Cuando se configura para crear nuevas instancias de algunos componentes para cada llamada al contenedor, el contenedor generalmente se olvida del objeto creado.
De: http://tutorials.jenkov.com/dependency-injection/dependency-injection-containers.html
La mayoría de los ejemplos citados para el uso de la inyección de dependencia, también podemos resolverlos utilizando 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 la forma en que lo usas lo que hace la diferencia!
Una vez utilicé StructureMap un contenedor DI para resolver un problema, luego lo rediseñé para que funcionara con una fábrica simple y eliminé las referencias a StructureMap.
¿Puede alguien decirme cuál es la diferencia entre ellos y dónde usar qué, cuál es la mejor práctica aquí?
Teoría
Hay dos puntos importantes a considerar:
Quien crea objetos
- [Fábrica]: tienes que escribir CÓMO se debe crear el objeto. Tienes una clase de fábrica separada que contiene lógica de creación.
- [Inyección de dependencia]: en la práctica, se realiza mediante marcos externos (por ejemplo, en Java, que sería spring / ejb / guice). La inyección ocurre "mágicamente" sin creación explícita de nuevos objetos
Qué tipo de objetos maneja:
- [Fábrica]: generalmente es responsable de la creación de objetos con estado
- [Inyecciones de dependencia] Es más probable que cree objetos sin estado
Ejemplo práctico de cómo utilizar la inyección de fábrica y de dependencia en un solo proyecto.
- Lo que queremos construir.
Módulo de aplicación para crear orden que contiene múltiples entradas llamadas línea de orden.
- Arquitectura
Supongamos que queremos crear la siguiente arquitectura de capa:
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. Bajas para operaciones en módulo de order
- Capa de dominio y uso de fábricas
Las entidades que estarán en la base de datos son Order y OrderLine. La orden puede tener múltiples líneas de orden.
Ahora viene parte importante del diseño. ¿Deberían los módulos fuera de este crear y gestionar OrderLines por su cuenta? No. La línea de orden debe existir solo cuando usted tiene orden asociada. Sería mejor si pudiera ocultar la implementación interna a clases externas.
¿Pero cómo crear Orden sin conocimiento acerca de OrderLines?
Fábrica
Alguien que desea crear un nuevo pedido utiliza OrderFactory (que ocultará detalles sobre el hecho de cómo creamos un pedido).
Así es como se verá dentro del IDE. Las clases fuera domain
paquete de domain
usarán OrderFactory
lugar del constructor dentro de Order
- Inyección de dependencia La inyección de dependencia se usa más comúnmente con capas sin estado como el repositorio y el servicio.
OrderRepository y OrderService son administrados por el marco de inyección de dependencias. El repositorio es responsable de administrar las operaciones de CRUD en la base de datos. El servicio inyecta el repositorio y lo usa para guardar / encontrar las clases de dominio correctas.
Al usar una fábrica, su código aún es realmente responsable de crear objetos. Por DI, usted subcontrata esa responsabilidad a otra clase o marco, que está separado de su código.
Binoj,
No creo que tengas que elegir uno sobre el otro.
El acto de mover una clase o interfaz dependiente a un constructor o establecedor de clase sigue el patrón DI. El objeto que pase al constructor o conjunto se puede implementar con Factory.
¿Cuándo usar? Utilice el patrón o patrones que están en su timonel desarrollador. ¿Con qué se sienten más cómodos y más fáciles de entender?
Con la inyección de dependencia, el cliente no necesita obtener sus dependencias por sí solo, todo está preparado de antemano.
Con las fábricas, alguien tiene que llamarlos para que los objetos generados lleguen al lugar donde se los necesita.
La diferencia radica principalmente en esta única línea donde se hace llamar a la fábrica y recuperar el objeto construido.
Pero con las fábricas tienes que escribir esta línea 1 en cualquier lugar donde necesites ese objeto. Con DI, solo tiene que crear el cableado (relación entre el uso y el objeto creado) una vez y solo basarse en la presencia del objeto después en todas partes. Por otro lado, DI a menudo requiere un poco más (cuánto depende del marco) de trabajo en el lado de la preparación.
Con una fábrica, puede agrupar interfaces relacionadas. Entonces, si los parámetros pasados se pueden agrupar en una fábrica, también es una buena solución para la constructor overinjection
en 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;
}
Mire el constructor, solo tiene que pasar el IAddressModelFactory
allí, así 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 CustomerController
muchos parámetros pasados, Sí, puede ver esto como, constructor overinjection
pero así es como funciona DI. Y no hay nada de malo en el CustomerController
.
*) El código es de nopCommerce.
Creo que 3 aspectos importantes gobiernan los objetos y su uso:
1. Creación de instancias (de una clase junto con la inicialización, si la hay).
2. Inyección (de la instancia así creada) donde se requiera.
3. Gestión del ciclo de vida (de la instancia así creada).
Usando el patrón de Fábrica, se logra el primer aspecto (creación de instancias) pero los dos restantes son cuestionables. La clase que usa otras instancias debe codificar las fábricas (en lugar de las instancias que se crean), lo que dificulta la capacidad de acoplamiento. Además, la administración del ciclo de vida de las instancias se convierte en un desafío en una aplicación grande donde una fábrica se usa en múltiples lugares (particularmente, si la fábrica no administra el ciclo de vida de la instancia que devuelve, se pone fea).
Usando un DI (del patrón IoC) por otro lado, todos los 3 se extraen fuera del código (para el contenedor DI) y el bean administrado no necesita nada sobre esta complejidad. Acoplamiento suelto , un objetivo arquitectónico muy importante puede lograrse 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 en lugar de fábricas.
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 de negocios relativamente estable en su construcción, el patrón de fábrica es fácil de entender, implementar y funciona bien.
OTOH, si tiene un proyecto que contiene numerosos tipos cuyas implementaciones espera cambiar a menudo, DI le brinda la flexibilidad a través de su configuración para hacerlo en tiempo de ejecución sin tener que volver a compilar sus fábricas.
Creo que DI es una forma de configurar o crear una instancia de un bean. El DI se puede hacer de muchas maneras, como constructor, definidor, etc.
El patrón de fábrica es solo otra forma de crear una instancia de los frijoles. este patrón se utilizará principalmente cuando tenga que crear objetos utilizando el patrón de diseño de fábrica, ya que al usar este patrón no configura las propiedades de un bean, solo ejemplifica el objeto.
Revisa este enlace: Inyección de dependencia.
Hay problemas que son fáciles de resolver con la inyección de dependencias 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), son:
IOC / DI es un completo ecosistema de objetos y servicios de dominio en sí mismo. Lo configura todo de la manera que especifique. Sus objetos y servicios de dominio están construidos por el contenedor, y no se construyen ellos mismos: por lo tanto, no tienen ninguna dependencia en el contenedor o en las fábricas. IOC / DI permite un grado de configuración extremadamente alto, con toda la configuración en un solo lugar (construcción del contenedor) en la capa más alta de su aplicación (la GUI, la interfaz web).
La fábrica abstrae parte de la construcción de sus objetos y servicios de dominio. Pero los objetos y servicios de dominio aún son responsables de descubrir cómo construirse ellos mismos y cómo obtener todas las cosas de las que dependen. Todas estas dependencias "activas" se filtran a través de todas las capas en su aplicación. No hay un solo lugar para configurar todo.
IOC 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 la creación de dependencias. La inyección de dependencia es constructor, definidor e interfaz. El núcleo de IOC es no depender de las clases concretas, sino definir el resumen de los métodos (por ejemplo, una interfaz / clase abstracta) y usar ese resumen para llamar al método de la clase concreta. Al igual que el patrón de Factory, devuelve la clase base o la interfaz. La inyección de dependencia similar utiliza la clase / interfaz base para establecer el valor de los objetos.
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 sobre qué IMO es la más importante y sobre la que se preguntó el OP. Así que permítanme reabrir este tema ...
Una vez que alguien me dijo que es la forma en que 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, obtiene estos últimos. En otro 10% de casos, usar Factory es solo correcto . 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: ".com",
useCookies: false, connectionTimeout: 120);
En este caso, no es posible obtener el client
de DI (o al menos requiere alguna solución fea). Entonces, 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.
La razón por la cual la inyección de dependencia (DI) y los patrones de fábrica son similares se debe a que 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 de Fábrica y el 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 de Fábrica, 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 del objeto que está utilizando el código.
Vale la pena señalar que los patrones de fábrica (o incluso los patrones de fábrica abstracta que son fábricas que devuelven nuevas fábricas que devuelven referencias de objetos) se pueden escribir para elegir dinámicamente o vincular al tipo o clase de objeto que se solicita en el tiempo de ejecución. Esto los hace muy similares (incluso más que a DI) al patrón Localizador de Servicio, que es otra implementación de la IoC.
El patrón de diseño de la fábrica 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 en lo que respecta a los patrones de diseño de IoC: inyectores inyectables, localizadores localizadores y refaccionamiento de fábricas.
Mis pensamientos:
Dependecy Injection: pasar colaboradores como parámetros a los constructores. Marco de inyección de dependencias: una fábrica genérica y configurable para crear los objetos para pasar como parámetros a los constructores.
Puede ver este enlace para ver una comparación de los dos (y otros) enfoques 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 pase en cada constructor).
Sé que esta pregunta es vieja pero me gustaría agregar mis cinco centavos,
Creo que la inyección de dependencia (DI) es, en muchos aspectos, un patrón de fábrica (FP) configurable, y en ese sentido, cualquier cosa que pueda hacer con DI puede hacerlo con dicha fábrica.
En realidad, si usa Spring, por ejemplo, tiene la opción de auto cablear recursos (DI) o hacer algo como esto:
MyBean mb = ctx.getBean("myBean");
Y luego usa esa instancia ''mb'' para hacer cualquier cosa. ¿No es eso una llamada a una fábrica que te devolverá una instancia?
La única diferencia real que observo entre la mayoría de los ejemplos de FP es que puede configurar qué "myBean" está en un xml o en otra clase, y un marco funcionará como fábrica, pero aparte de eso es lo mismo, y usted sin duda, puede tener una Factory que lee un archivo de configuración o obtiene la implementación que necesita.
Y si me preguntas por 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, en primer lugar, para que sepa cuál es la implementación que se está utilizando para cualquier bean con el que realice el DI, debe ir a la configuración en sí.
pero ... ¿qué hay de esa promesa de que no tendrá que conocer la implementación del objeto que está utilizando? pfft ¿seriamente? cuando usas un enfoque como este ... ¿no eres el mismo que escribe la implementación? e incluso si no lo hace, ¿no está usted casi todo el tiempo mirando cómo la implementación hace lo que se supone que debe hacer?
y para una última cosa, no importa cuánto te prometa un marco DI que construirás cosas desacopladas de él, sin dependencias de sus clases, si estás usando un marco, lo construyes todo en el mismo, si tienes que cambiar el enfoque o el marco no será una tarea fácil ... ¡NUNCA! ... pero, dado que usted construye todo alrededor de ese marco particular en lugar de preocuparse por cuál es la mejor solución para su negocio, entonces se enfrentará a un problema de biiig al hacer eso.
De hecho, la única aplicación de negocios real para un enfoque de FP o DI que puedo ver es si necesita cambiar las implementaciones que se están utilizando en el tiempo de ejecución , pero al menos los marcos que conozco no le permiten hacer eso, tienen que abandonar Todo perfecto en la configuración en el momento del desarrollo y si necesita usar otro enfoque.
Entonces, si tengo una clase que se desempeña 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 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 tendrá que 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 fábrica para obtener la implementación correcta en el tiempo de ejecución en función de la empresa del usuario registrado? Ahora eso sería útil. Puede simplemente agregar un nuevo archivo jar con las nuevas clases y establecer las reglas, incluso en el tiempo de ejecución (o agregar un nuevo archivo de configuración si deja esta opción abierta), sin cambios en las clases existentes. ¡Esto sería una fábrica dinámica!
¿No sería eso más útil que tener que escribir dos configuraciones para cada empresa e incluso tener dos aplicaciones diferentes para cada empresa?
Puede decirme que no necesito hacer el cambio en el tiempo de ejecución, por lo que configuro la aplicación, y si heredo la clase o uso otra implementación, solo cambio la configuración y la redistribución. Ok, eso también se puede hacer con una fábrica. Y sé honesto, ¿cuántas veces haces esto? tal vez solo cuando tenga una aplicación que se vaya a utilizar en otro lugar de su compañía, y le pase el código a otro equipo, y ellos hagan 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 si está abierta para que me mates.
Sugeriría mantener los conceptos claros y simples. La inyección de dependencias es más bien un patrón arquitectónico para acoplar elementos de software de forma flexible. 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 puede ser llamado como una herramienta para implementar DI. La inyección de dependencia se puede implementar de muchas maneras, como DI utilizando constructores, utilizando mapas xml, etc.
Tuve la misma pregunta en cuanto leí sobre DI y terminé en esta publicación. Así que, finalmente, esto es lo que entendí, pero corríjame si me equivoco.
"Hace mucho tiempo había pequeños reinos con sus propios órganos de gobierno que controlaban y tomaban decisiones basadas en sus propias reglas escritas. Más tarde formaron 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 las "fábricas".
El gran gobierno es el "Inyector de dependencia".
Un marco de inyección es una implementación del patrón de fábrica.
Todo depende de sus necesidades. Si necesita implementar el patrón de fábrica en una aplicación, es muy probable que sus requisitos se cumplan con una de las múltiples implementaciones del marco de inyección.
Solo debe implementar su propia solución si sus requisitos no pueden cumplirse con cualquiera de los marcos de terceros. Cuanto más código escriba, más código tendrá que mantener. El código es una responsabilidad no un activo.
Los argumentos sobre la implementación que debe utilizar no son tan importantes como comprender las necesidades arquitectónicas de su aplicación.
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 desde la creación de objetos, que admite uno de los patrones de diseño llamados "Encapsular lo que varía".
De un valor nominal se ven igual
En términos muy simples, Factory Pattern, un Creational Pattern ayuda a crearnos un objeto: "Definir una interfaz para crear un objeto". Si tenemos un tipo de valor clave de grupo de objetos (por ejemplo, Diccionario), al pasar 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, Objeto, Unidad, etc.) por otro lado parece estar haciendo lo mismo.
Pero ... "no reinventes la rueda"
Desde una perspectiva arquitectónica es una capa vinculante y "No reinventar la rueda".
Para una aplicación de nivel empresarial, el concepto de DI es más bien una capa arquitectónica que define dependencias. Para simplificar esto aún más, puede pensar en esto como un proyecto de biblioteca de clase separado, que hace la resolución de dependencias. La aplicación principal depende de este proyecto donde el resolvedor 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, simulacros y pruebas unitarias, etc.). Desde que hizo referencia al mapa de estructura, consulte la lista de características del mapa de estructura . Es claramente más que simplemente resolver un simple Mapeo 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 construya, necesita hacer una elección. 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 o más llamadas de base de datos 1, 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 tener una capa DI con un marco y dejar espacio para cambiar el marco DI que usa (Use una fachada en la aplicación principal (Aplicación Web, Web Api, Desktop ..etc.).
En términos simples, el método de inyección de dependencia frente a fábrica implica un mecanismo de empuje contra tracción, respectivamente.
Con mecanismo de tracción: la clase tiene dependencia indirecta del Método de Fábrica que a su vez depende de las clases concretas.
Con 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 suelto.
Con el método Factory, la responsabilidad aún reside en la clase (aunque indirectamente) para crear un nuevo objeto en el que, al igual que con la inyección de dependencia, esa responsabilidad se subcontrata (a costa de filtrar la abstracción)
Inyección de dependencia
En lugar de crear una instancia de las partes, un automóvil solicita las piezas que necesita para funcionar.
class Car
{
private Engine;
private SteeringWheel;
private Tires tires;
public Car(Engine engine, SteeringWheel wheel, Tires tires)
{
this.Engine = engine;
this.SteeringWheel = wheel;
this.Tires = tires;
}
}
Fábrica
Pone las piezas juntas para hacer un objeto completo y oculta el tipo 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 puedes ver, Fábricas y DI se complementan.
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 considerara el método como una caja negra, no tendría 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 por 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 a una fábrica solo para construir el auto cuando el auto podría ser construido fuera del método y pasado.
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 asombroso y es la base de la que obtuve mi ejemplo. http://www.youtube.com/watch?v=XcT4yYu_TTs
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 como a continuación
- ¿Cuándo creará la fábrica el 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 son manejados por inyección de dependencia.
Inyección de dependencia
Puedes tener diferentes formas en las que puedes inyectar dependencia. Por simplicidad 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();
}
}
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
) tenía que instanciar nuevos objetos de otra clase ( Child
), y aquellos 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, Parent
tiene que recibir DepX
instancias solo para pasarlas al Child
constructor. Problemas con esto:
-
Parent
tiene más conocimiento deChild
lo que debería -
Parent
Tiene más colaboradores de los que debería. - Agregar dependencias
Child
implica cambiarParent
Esto es cuando me di cuenta de Factory
que cabría perfectamente aquí:
- Oculta todos los parámetros, excepto los verdaderos de la
Child
clase, como se ve porParent
- Encapsula el conocimiento de la creación de un
Child
, que puede ser centralizado en la configuración DI.
Esta es la Parent
clase simplificada y la ChildFactory
clase:
@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);
}
}
En mi opinión, el uso de la inyección de dependencia es mucho mejor si: 1. está implementando su código en una partición pequeña, ya que se maneja bien al desacoplar 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 puedes simular 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á desacoplada de forma flexible.
Uso ambos para crear una estrategia de Inversión de control con más facilidad de lectura para los desarrolladores que necesitan mantenerla después de mí.
Uso una Fábrica para crear mis diferentes objetos de Capa (Negocios, Acceso a Datos).
ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();
Otro desarrollador verá esto y cuando crea un objeto de Capa de negocios, busca en BusinessFactory e Intellisense le da al desarrollador todas las posibles Capas de negocios para crear. No tiene que jugar el juego, encuentra 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 asegurarse de que la inyección de dependencia sea capaz de cambiar las cosas fácilmente. Crear tu propia inyección de dependencia personalizada es ridículo, así que uso Unity. Dentro de CreateCarBusiness () le pido a Unity que resuelva qué clase pertenece a esto y que es de por vida.
Así que mi código de la 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 ámbitos de mis objetos que utilizo, 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 la base de datos a una capa de acceso a los datos con código personalizado 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.