La inversión de dependencia en OOP significa que usted codifica contra una interfaz que luego es proporcionada por una implementación en un objeto.
Los lenguajes que admiten funciones de lenguaje superior a menudo pueden resolver problemas simples de inversión de dependencia al pasar el comportamiento como una función en lugar de un objeto que implementa una interfaz en el sentido OO.
En dichos lenguajes, la firma de la función puede convertirse en la interfaz y se pasa una función en lugar de un objeto tradicional para proporcionar el comportamiento deseado. El agujero en el patrón del medio es un buen ejemplo de esto.
Le permite lograr el mismo resultado con menos código y más expresividad, ya que no necesita implementar una clase completa que se ajuste a una interfaz (OOP) para proporcionar el comportamiento deseado para la persona que llama. En cambio, puede pasar una definición de función simple. En resumen: el código suele ser más fácil de mantener, más expresivo y más flexible cuando se utilizan funciones de orden superior.
Un ejemplo en C #
Enfoque tradicional:
public IEnumerable<Customer> FilterCustomers(IFilter<Customer> filter, IEnumerable<Customers> customers)
{
foreach(var customer in customers)
{
if(filter.Matches(customer))
{
yield return customer;
}
}
}
//now you've got to implement all these filters
class CustomerNameFilter : IFilter<Customer> /*...*/
class CustomerBirthdayFilter : IFilter<Customer> /*...*/
//the invocation looks like this
var filteredDataByName = FilterCustomers(new CustomerNameFilter("SomeName"), customers);
var filteredDataBybirthDay = FilterCustomers(new CustomerBirthdayFilter(SomeDate), customers);
Con funciones de orden superior:
public IEnumerable<Customer> FilterCustomers(Func<Customer, bool> filter, IEnumerable<Customers> customers)
{
foreach(var customer in customers)
{
if(filter(customer))
{
yield return customer;
}
}
}
Ahora la implementación y la invocación se vuelven menos engorrosas. Ya no necesitamos suministrar una implementación de IFilter. Ya no necesitamos implementar clases para los filtros.
var filteredDataByName = FilterCustomers(x => x.Name.Equals("CustomerName"), customers);
var filteredDataByBirthday = FilterCustomers(x => x.Birthday == SomeDateTime, customers);
Por supuesto, esto ya lo puede hacer LinQ en C #. Acabo de usar este ejemplo para ilustrar que es más fácil y más flexible usar funciones de orden superior en lugar de objetos que implementan una interfaz.
IFilter<Customer>
no es hacer cumplir en absoluto. La función de orden superior es mucho más flexible, lo cual es un gran beneficio, y poder escribirlas en línea es otro gran beneficio. Las lambdas también son mucho más fáciles de capturar variables locales.public delegate bool CustomerFilter(Customer customer)
. en lenguajes funcionales puros como haskell, los tipos de alias son triviales:type customerFilter = Customer -> Bool
Si quieres cambiar el comportamiento de una función
podrías pasar otra función
que implementa el comportamiento que desea que sea diferente.
"doThisWith" es una función de orden superior porque toma otra función como argumento.
Por ejemplo, podrías tener
fuente
Respuesta corta:
La inyección de dependencia clásica / inversión de control utiliza interfaces de clase como marcador de posición para la funcionalidad dependiente. Esta interfaz es implementada por una clase.
En lugar de Interface / ClassImplementation, muchas dependencias pueden implementarse más fácilmente con una función delegada.
Puede encontrar un ejemplo para ambos en c # en ioc-factory-pros-and-contras-for-interface-versus-delegates .
fuente
Compara esto:
con:
La segunda versión es la forma en que Java 8 reduce el código repetitivo (bucle, etc.) al proporcionar funciones de orden superior como las
filter
que le permiten pasar el mínimo básico (es decir, la dependencia a inyectar, la expresión lambda).fuente
Piggy-backing del ejemplo de LennyProgrammers ...
Una de las cosas que los otros ejemplos perdieron es que puede usar funciones de orden superior junto con la aplicación de función parcial (PFA) para unir (o "inyectar") dependencias en una función (a través de su lista de argumentos) para crear una nueva función.
Si en lugar de:
nosotros (para ser convencionales en la forma en que generalmente se hace PFA) tenemos la función de trabajador de bajo nivel como (intercambio de orden arg):
Entonces podemos aplicar parcialmente doThisWith así:
Lo que nos permite más tarde utilizar la nueva función de esta manera:
O incluso:
Ver también: https://ramdajs.com/docs/#partial
... y, sí, los sumadores / multiplicadores son ejemplos poco imaginativos. Un mejor ejemplo sería una función que toma mensajes y los registra o los envía por correo electrónico dependiendo de lo que la función "consumidor" haya pasado como dependencia.
Extendiendo esta idea, las listas de argumentos aún más largas se pueden reducir progresivamente a funciones cada vez más especializadas con listas de argumentos cada vez más cortas, y, por supuesto, cualquiera de estas funciones se puede pasar a otras funciones como dependencias para aplicar parcialmente.
OOP es bueno si necesita un conjunto de cosas con múltiples operaciones estrechamente relacionadas, pero se convierte en un trabajo para hacer un montón de clases cada una con un único método público de "hazlo", a la "El Reino de los sustantivos".
fuente