¿Cómo se relaciona la inversión de dependencia con las funciones de orden superior?

38

Hoy acabo de ver este artículo que describe la relevancia del principio SOLID en F # development-

F # y principios de diseño - SOLID

Y mientras abordaba el último - "Principio de inversión de dependencia", el autor dijo:

  

Desde un punto de vista funcional, estos contenedores y conceptos de inyección se pueden resolver con una función simple de orden superior, o un patrón de tipo de agujero en el medio que está integrado en el lenguaje.

Pero él no lo explicó más. Entonces, mi pregunta es, ¿cómo se relaciona la inversión de dependencia con las funciones de orden superior?

    
pregunta Gulshan 25.08.2011 - 06:11

5 respuestas

35

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 idiomas, 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 medio es un buen ejemplo para esto.

Le permite obtener 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 su lugar, simplemente puede pasar una definición de función simple. En resumen: el código es a menudo más fácil de mantener, más expresivo y más flexible cuando uno usa 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.

    
respondido por el Falcon 25.08.2011 - 09:20
5

Si desea cambiar el comportamiento de una función

doThis(Foo)

podrías pasar otra función

doThisWith(Foo, anotherFunction)

que implementa el comportamiento que quieres que sea diferente.

"doThisWith" es una función de orden superior porque toma otra función como argumento.

Por ejemplo, podrías tener

storeValues(Foo, writeToDatabase)
storeValues(Foo, imitateDatabase)
    
respondido por el LennyProgrammers 25.08.2011 - 09:43
4

Respuesta corta:

La inyección / dependencia de control de dependencia clásica utiliza una interfaz 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 se pueden implementar más fácilmente con una función de delegado.

Encontrará un ejemplo para ambos en c # en ioc- factory-pros-and-contras-para-interface-versus-delegates .

    
respondido por el k3b 31.05.2012 - 14:07
0

Compara esto:

String[] names = {"Fred", "Susan"};
List<String> namesBeginningWithS = new LinkedList<String>();
for (String name : names) {
    if (name.startsWith("S")) {
        namesBeginningWithS.add(name);
    }
}

con:

String[] names = {"Fred", "Susan"};
List<String> namesBeginningWithS = names.stream().filter(n <- n.startsWith("S")).collect();

La segunda versión es la forma de Java 8 de reducir el código de repetición (bucle, etc.) al proporcionar funciones de orden superior como filter , que le permite pasar el mínimo (es decir, la dependencia a inyectar, la expresión lambda).

    
respondido por el Sridhar-Sarnobat 09.08.2017 - 23:18
0

Ejemplo de LennyProgrammers que se extrae a cuestas ...

Una de las cosas que otros ejemplos faltaron es que puede usar funciones de orden superior junto con la aplicación de función parcial (PFA) para vincular (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:

doThisWith(Foo, anotherFunction)

nosotros (para ser convencionales en la forma en que P.F.A. generalmente se realiza) tenemos la función de trabajador de bajo nivel como (intercambiando orden arg):

doThisWith( anotherFunction, Foo )

Entonces podemos aplicar parcialmente hacer esto con esto:

doThis = doThisWith( anotherFunction )  // note that "Foo" is still missing, argument list is partial

Lo que nos permite usar la nueva función más adelante de esta forma:

doThis(Foo)

O incluso:

doThat = doThisWith( yetAnotherDependencyFunction )
...
doThat( Bar )

Vea también: enlace

... y, sí, los sumadores / multiplicadores son ejemplos poco imaginativos. Un ejemplo mejor sería una función que toma mensajes y los registra o envía por correo electrónico según la función de "consumidor" que se haya pasado como dependencia.

Extendiendo esta idea, las listas de argumentos aún más largas pueden reducirse progresivamente a funciones cada vez más especializadas con listas de argumentos cada vez más cortas y, por supuesto, cualquiera de estas funciones puede transferirse a otras funciones como dependencias que se aplicarán parcialmente.

OOP es bueno si necesitas un conjunto de cosas con múltiples operaciones estrechamente relacionadas, pero se convierte en una tarea para hacer un montón de clases, cada una con un único método público "hazlo", a la "El Reino de los Sustantivos ".

    
respondido por el Roboprog 14.09.2018 - 03:56

Lea otras preguntas en las etiquetas