Inversão de dependência no OOP significa que você codifica contra uma interface que é fornecida por uma implementação em um objeto.
Os idiomas que suportam funções de idioma superior geralmente podem resolver problemas simples de inversão de dependência, passando o comportamento como uma função em vez de um objeto que implementa uma interface no sentido OO.
Nessas linguagens, a assinatura da função pode se tornar a interface e uma função é passada em vez de um objeto tradicional para fornecer o comportamento desejado. O buraco no padrão do meio é um bom exemplo disso.
Permite obter o mesmo resultado com menos código e mais expressividade, pois você não precisa implementar uma classe inteira que esteja em conformidade com uma interface (OOP) para fornecer o comportamento desejado para o chamador. Em vez disso, você pode simplesmente passar uma definição de função simples. Em resumo: o código geralmente é mais fácil de manter, mais expressivo e mais flexível quando se usa funções de ordem superior.
Um exemplo em c #
Abordagem 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);
Com funções de ordem superior:
public IEnumerable<Customer> FilterCustomers(Func<Customer, bool> filter, IEnumerable<Customers> customers)
{
foreach(var customer in customers)
{
if(filter(customer))
{
yield return customer;
}
}
}
Agora a implementação e a invocação se tornam menos complicadas. Não precisamos mais fornecer uma implementação do IFilter. Não precisamos mais implementar classes para os filtros.
var filteredDataByName = FilterCustomers(x => x.Name.Equals("CustomerName"), customers);
var filteredDataByBirthday = FilterCustomers(x => x.Birthday == SomeDateTime, customers);
Obviamente, isso já pode ser feito pelo LinQ em C #. Acabei de usar este exemplo para ilustrar que é mais fácil e flexível usar funções de ordem superior em vez de objetos que implementam uma interface.
IFilter<Customer>
não é nenhuma aplicação. A função de ordem superior é muito mais flexível, o que é um grande benefício, e poder escrevê-las em linha é outro grande benefício. Lambdas também são muito mais fáceis de capturar variáveis locais.public delegate bool CustomerFilter(Customer customer)
. em linguagens funcionais puras como Haskell, aliasing tipos é trivial:type customerFilter = Customer -> Bool
Se você deseja alterar o comportamento de uma função
você poderia passar outra função
o que implementa o comportamento que você deseja que seja diferente.
"doThisWith" é uma função de ordem superior porque assume outra função como argumento.
Por exemplo, você poderia ter
fonte
Resposta curta:
A Injeção de Dependência Clássica / Inversão de Controle usa interfaces de classe como espaço reservado para a funcionalidade dependente. Essa interface é implementada por uma classe.
Em vez de implementação de interface / classe, muitas dependências podem ser implementadas com mais facilidade com uma função delegada.
Você encontra um exemplo para ambos no c # em ioc-factory-pros-e-contras-para-interface-contra-delegados .
fonte
Compare isto:
com:
A segunda versão é a maneira do Java 8 de reduzir o código padrão (looping etc.), fornecendo funções de ordem superior, como as
filter
que permitem passar o mínimo necessário (ou seja, a dependência a ser injetada - a expressão lambda).fonte
Piggy-backing fora do exemplo LennyProgrammers ...
Uma das coisas que os outros exemplos perderam é que você pode usar funções de ordem superior junto com o aplicativo de função parcial (PFA) para vincular (ou "injetar") dependências em uma função (por meio de sua lista de argumentos) para criar uma nova função.
Se em vez de:
nós (para ser convencional na maneira como o PFA geralmente é feito) temos a função de trabalhador de baixo nível como (trocando a ordem do argumento):
Em seguida, podemos aplicar parcialmente o doThisWith da seguinte forma:
O que nos permite usar a nova função mais tarde:
Ou até:
Veja também: https://ramdajs.com/docs/#partial
... e, sim, somadores / multiplicadores são exemplos sem imaginação. Um exemplo melhor seria uma função que recebe mensagens e as registra ou envia por e-mail, dependendo do que a função "consumidor" passou como dependência.
Estendendo essa idéia, listas de argumentos ainda mais longas podem ser progressivamente reduzidas a funções cada vez mais especializadas, com listas de argumentos cada vez mais curtas e, é claro, qualquer uma dessas funções pode ser passada para outras funções como dependências a serem parcialmente aplicadas.
OOP é bom se você precisar de um conjunto de coisas com várias operações estreitamente relacionadas, mas se transforma em make-work para criar um monte de classes, cada uma com um único método público "do it", como "O Reino dos Substantivos".
fonte