Esta es una decisión de diseño que parece surgir bastante: cómo pasar el contexto a través de un método que no lo necesita a un método que sí lo necesita. ¿Hay una respuesta correcta o depende del contexto?
Código de muestra que requiere una solución
// needs the dependency
function baz(session) {
session('baz');
}
// doesn't care about the dependency
function bar() {
baz();
}
// needs the dependency
function foo(session) {
session('foo')
bar();
}
// creates the dependency
function start() {
let session = new Session();
foo(session);
}
Soluciones posibles
- hilo local
- global
- objeto de contexto
- pasar la dependencia a través de
- curry baz y pasarlo a la barra con la dependencia establecida como el primer argumento
- inyección de dependencia
Ejemplos de dónde viene
Procesamiento de solicitudes HTTP
Con frecuencia se usan objetos de contexto en forma de atributos de solicitud: consulte expressjs, Java Servlets o .net's owin.
Inicio sesión
Para el registro de Java, la gente a menudo usa globals / singletons. Vea los patrones típicos de log4j / commons logging / java logging.
Actas
Los locales de subprocesos a menudo se usan para mantener una transacción o sesión asociada con una cadena de llamadas a métodos para evitar la necesidad de pasarlos como parámetros a todos los métodos que no los necesitan.
design-patterns
Jamie McCrindle
fuente
fuente
Respuestas:
La única respuesta justa es que depende de los modismos de su paradigma de programación. Si está utilizando OO, es casi seguro que sea incorrecto pasar una dependencia de un método a otro. Es un olor a código en OO. De hecho, ese es uno de los problemas que OO resuelve: un objeto arregla un contexto. Entonces, en OO, un enfoque correcto (siempre hay otras formas) es entregar la dependencia a través de un constructor o propiedad. Un comentarista menciona "Inyección de dependencia" y eso es perfectamente legítimo, pero no es estrictamente necesario. Solo proporcione la dependencia para que esté disponible como miembro para
foo
ybaz
.Mencionas curry, así que asumiré que la programación funcional no está descartada. En ese caso, un equivalente filosófico del contexto del objeto es el cierre. Cualquier enfoque que, una vez más, arregle la dependencia para que esté disponible para los dependientes funciona bien. El curry es uno de esos enfoques (y te hace sonar inteligente). Solo recuerde que hay otras formas de cerrar una dependencia. Algunos de ellos son elegantes y otros horribles.
No te olvides de la programación orientada a aspectos . Parece haber caído en desgracia en los últimos años, pero su objetivo principal es resolver exactamente el problema que usted describe. De hecho, el ejemplo clásico de Aspect es el registro. En AOP, la dependencia se agrega automáticamente después de escribir otro código. La gente de AOP llama a esto " tejido ". Los aspectos comunes están entretejidos en el código en los lugares apropiados. Esto hace que su código sea más fácil de pensar y es bastante genial, pero también agrega una nueva carga de prueba. Necesitará una forma de determinar que sus artefactos finales son sólidos. AOP también tiene respuestas para eso, así que no te sientas intimidado.
fuente
Si
bar
depende debaz
, lo que a su vez requieredependency
, entonces también lobar
requieredependency
para usarlo correctamentebaz
. Por lo tanto, los enfoques correctos serían pasar la dependencia a través de un parámetrobar
o currybaz
y pasar eso abar
.El primer enfoque es más sencillo de implementar y leer, pero crea un acoplamiento entre
bar
ybaz
. El segundo enfoque elimina ese acoplamiento, pero podría dar como resultado un código menos claro. Por lo tanto, qué enfoque es mejor dependerá de la complejidad y el comportamiento de ambas funciones. Por ejemplo, si tienebaz
odependency
tiene efectos secundarios, la facilidad de prueba probablemente será un gran impulsor para elegir la solución.Sugeriría que todas las demás opciones que proponga sean de naturaleza "hacky" y puedan generar problemas tanto con las pruebas como con errores difíciles de rastrear.
fuente
dependency
por parámetros es la inyección de dependencia?Hablando filosóficamente
Estoy de acuerdo con la preocupación de David Arno .
Estoy leyendo el OP en busca de soluciones de implementación. Sin embargo, la respuesta es cambiar el diseño . "Patrones"? El diseño OO es, se podría decir, todo sobre el contexto. Es una vasta hoja de papel en blanco llena de posibilidades.
Tratar con el código existente es un contexto diferente, bueno.
Estoy trabajando en 'zactly el mismo problema ahora mismo. Bueno, estoy arreglando los cientos de líneas de código copiar y pegar que se hicieron para que se pueda inyectar un valor.
Modularizar el código
Tiré 600 líneas de código duplicado y luego las refactoricé para que en lugar de "A llame a B llame a C llame a D ..." Tengo "Llamar A, regresar, Llamar B, regresar, Llamar C ...". Ahora solo necesitamos inyectar el valor en uno de esos métodos, digamos el método E.
Agregue un parámetro predeterminado al constructor. Las llamadas existentes no cambian: "opcional" es la palabra clave aquí. Si no se pasa un argumento, se utiliza el valor predeterminado. Luego, solo 1 cambio de línea para pasar la variable a la estructura modular refactorizada; y un pequeño cambio en el método E para usarlo.
Cierres
Un hilo de programadores: "¿Por qué un programa usaría un cierre?"
Básicamente, está inyectando valores en un método que devuelve un método personalizado con los valores. Ese método personalizado se ejecuta posteriormente.
Esta técnica le permitiría modificar un método existente sin cambiar su firma.
fuente