design-patterns dependency-injection strategy-pattern

design patterns - ¿Cuál es la diferencia entre el patrón de estrategia y la inyección de dependencia?



design-patterns dependency-injection (9)

Amigo, la inyección de dependencia es un patrón más general, y se trata de la dependencia de las abstracciones, no de las concreciones y es una parte de cada patrón, pero el patrón de la estrategia es una solución a un problema más específico

Esta es la definición de wikipedia:

DI:

La inyección de dependencia (DI) en la programación de computadoras orientada a objetos es un patrón de diseño con un principio central de separación de comportamiento de resolución de dependencia. En otras palabras: una técnica para desacoplar componentes de software altamente dependientes.

Patrón de estrategia:

En la programación de computadoras, el patrón de estrategia (también conocido como patrón de política) es un patrón de diseño de software particular, mediante el cual se pueden seleccionar algoritmos en tiempo de ejecución.

El patrón de estrategia está destinado a proporcionar un medio para definir una familia de algoritmos, encapsular cada uno como un objeto y hacerlos intercambiables. El patrón de estrategia permite que los algoritmos varíen independientemente de los clientes que los usan.

El patrón de estrategia y la inyección de dependencia nos permiten configurar / inyectar objetos en tiempo de ejecución. ¿Cuál es la diferencia entre el patrón de estrategia y la inyección de dependencia?


En realidad, la inyección de dependencia también se ve muy similar al patrón de Bridge. Para mí (y de acuerdo con la definición), el patrón de Bridge es para acomodar diferentes versiones de la implementación, mientras que el patrón de Estrategia es para la lógica totalmente diferente. Pero el código de muestra parece que está usando DI. ¿Entonces tal vez DI es solo una técnica o implementación?


La DI y la Estrategia funcionan de la misma manera, pero la Estrategia se usa para dependencias más finas y de corta duración.

Cuando un objeto se configura con una estrategia "fija", por ejemplo cuando se construye el objeto, la distinción entre estrategia y DI se difumina. Pero en un escenario de DI, es más inusual que las dependencias de los objetos cambien durante su vida útil, mientras que esto no es infrecuente con la Estrategia.

Además, puede pasar estrategias como argumentos a métodos, mientras que el concepto relacionado de inyección de argumentos de método no está muy extendido y se usa principalmente en el contexto de pruebas automatizadas solamente.

La estrategia se centra en la intención y lo alienta a crear una interfaz con diferentes implementaciones que obedecen al mismo contrato de comportamiento. DI es más acerca de tener una implementación de algún comportamiento y proporcionarla.

Con DI puede descomponer su programa por otras razones además de poder intercambiar partes de la implementación. Una interfaz utilizada en DI con una sola implementación es muy común. Una "estrategia" con una sola implementación concreta (nunca) no es un problema real, pero probablemente esté más cerca de DI.


La diferencia es lo que están tratando de lograr. El patrón de estrategia se utiliza en situaciones en las que sabe que desea intercambiar implementaciones. Como ejemplo, es posible que desee formatear los datos de diferentes maneras: podría utilizar el patrón de estrategia para intercambiar un formateador XML o un formateador CSV, etc.

La inyección de dependencia es diferente en que el usuario no está intentando cambiar el comportamiento en tiempo de ejecución. Siguiendo el ejemplo anterior, podríamos estar creando un programa de exportación XML que utiliza un formateador XML. En lugar de estructurar el código de esta manera:

public class DataExporter() { XMLFormatter formatter = new XMLFormatter(); }

Usted ''inyectaría'' el formateador en el constructor:

public class DataExporter { IFormatter formatter = null; public DataExporter(IDataFormatter dataFormatter) { this.formatter = dataFormatter; } } DataExporter exporter = new DataExporter(new XMLFormatter());

Hay algunas justificaciones para la inyección de dependencia, pero la principal es para la prueba. Es posible que tenga un caso en el que tenga un motor de persistencia de algún tipo (como una base de datos). Sin embargo, puede ser un dolor utilizar una base de datos real cuando ejecuta pruebas repetidamente. Por lo tanto, para sus casos de prueba, inyectaría una base de datos ficticia, para no incurrir en esa sobrecarga.

Al usar este ejemplo, puede ver la diferencia: siempre planeamos usar una estrategia de almacenamiento de datos, y es la que pasamos (la instancia de base de datos real). Sin embargo, en el desarrollo y las pruebas, queremos usar diferentes dependencias, por lo que inyectamos diferentes concreciones.


La estrategia es un campo para usar tus habilidades de inyección de dependencia. Las formas reales de implementar la inyección de dependencia son las siguientes:

  1. Eventos
  2. Archivos de configuración de la unidad / mapa de estructura (o programáticamente) etc.
  3. Métodos de extensión
  4. Patrón abstracto de la fábrica
  5. Patrón de inversión de control (utilizado tanto por estrategia como por Abstract Factory)

Hay una cosa que hace que la estrategia se distinga. Como saben en Unity, cuando se inicia la aplicación, todas las dependencias están configuradas y no podemos cambiarlo más. Pero la estrategia soporta el cambio de dependencia en tiempo de ejecución. ¡Pero NOSOTROS tenemos que administrar / inyectar la dependencia, no la responsabilidad de la Estrategia!

En realidad la estrategia no habla de la inyección de dependencia. Si es necesario, se puede hacer a través de Abstract Factory dentro de un patrón de Estrategia. La estrategia solo habla de crear una familia de clases con interfaz y "jugar" con ella. Mientras jugamos, si encontramos que las clases están en un nivel diferente, tenemos que inyectarnos nosotros mismos, pero no el trabajo de Estrategia.


La inyección de dependencia es un refinamiento del patrón de estrategia que explicaré brevemente. A menudo es necesario elegir entre varios módulos alternativos en tiempo de ejecución. Todos estos módulos implementan una interfaz común para que puedan usarse indistintamente. El propósito del patrón de estrategia es eliminar la carga de decidir cuál de los módulos usar (es decir, qué "estrategia concreta" o dependencia) al encapsular el proceso de toma de decisiones en un objeto separado que llamaré el objeto de estrategia.

La inyección de dependencia refina el patrón de estrategia no solo decidiendo qué estrategia concreta utilizar, sino también creando una instancia de la estrategia concreta e "inyectándola" de nuevo en el módulo de llamada. Esto es útil incluso si solo existe una única dependencia, ya que el conocimiento de cómo administrar (inicializar, etc.) la instancia de la estrategia concreta también se puede ocultar dentro del objeto de la estrategia.


Las estrategias son cosas de nivel superior que se utilizan para cambiar la forma en que se calculan las cosas. Con la inyección de dependencia, puede cambiar no solo la forma en que se calculan las cosas, sino también lo que está allí.

Para mí, queda claro cuando se utilizan pruebas unitarias. Para la ejecución del código de producción, tiene todos los datos ocultos (es decir, privados o protegidos); mientras que, con las pruebas unitarias, la mayoría de los datos son públicos, así que puedo verlos con los Asserts.

Ejemplo de estrategia:

public class Cosine { private CalcStrategy strat; // Constructor - strategy passed in as a type of DI public Cosine(CalcStrategy s) { strat = s; } } public abstract class CalcStrategy { public double goFigure(double angle); } public class RadianStrategy extends CalcStrategy { public double goFigure(double angle) { return (...); } } public class DegreeStrategy extends CalcStrategy { public double goFigure(double angle) { return (...); } }

Tenga en cuenta que no hay datos públicos que sean diferentes entre las estrategias. Tampoco hay métodos diferentes. Ambas estrategias comparten las mismas funciones y firmas.

Ahora para la inyección de dependencia:

public class Cosine { private Calc strat; // Constructor - Dependency Injection. public Cosine(Calc s) { strat = s; } } public class Calc { private int numPasses = 0; private double total = 0; private double intermediate = 0; public double goFigure(double angle) { return(...); } public class CalcTestDouble extends Calc { // NOTICE THE PUBLIC DATA. public int numPasses = 0; public double total = 0; public double intermediate = 0; public double goFigure(double angle) { return (...); } }

Utilizar:

public CosineTest { @Test public void testGoFigure() { // Setup CalcTestDouble calc = new CalcTestDouble(); Cosine instance = new Cosine(calc); // Exercise double actualAnswer = instance.goFigure(0.0); // Verify double tolerance = ...; double expectedAnswer = ...; assertEquals("GoFigure didn''t work!", expectedAnswer, actualAnswer, tolerance); int expectedNumPasses = ...; assertEquals("GoFigure had wrong number passes!", expectedNumPasses, calc.numPasses); double expectedIntermediate = ...; assertEquals("GoFigure had wrong intermediate values!", expectedIntermediate, calc.intermediate, tolerance); } }

Observe las 2 últimas comprobaciones. Utilizaron los datos públicos en el doble de prueba que se inyectó en la clase bajo prueba. No pude hacer esto con el código de producción debido al principio de ocultación de datos. No quise tener un código de prueba de propósito especial insertado en el código de producción. Los datos públicos tenían que estar en una clase diferente.

Se inyectó la prueba doble. Eso es diferente a solo una estrategia ya que afectó los datos y no solo las funciones.


Puede usar DI como un patrón de estrategia, por lo que puede intercambiar el algoritmo que se necesita para cada cliente, pero DI puede ir más allá, ya que es una manera de simplemente desacoplar las partes de una aplicación, que no sería parte de El patrón de estrategia.

Sería arriesgado decir que la DI es solo un patrón de estrategia cuyo nombre ha cambiado, ya que eso comienza a diluir cuál es el patrón de estrategia para la OMI.


Si consideramos los principios SÓLIDOS, utilizamos el Patrón de Estrategia para el Principio Abierto Abierto y la Inyección de Dependencia para el Principio de Inversión de Dependencia