Princípio de Inversão de Dependência vs “Programe para uma interface, não para uma implementação”

12

Estou tentando entender como o Princípio da Inversão da Dependência difere do princípio "programa para uma interface, não uma implementação".

Entendo o que significa "Programa para uma interface, não para uma implementação". Também entendo como isso permite projetos mais flexíveis e sustentáveis.

Mas não entendo como o Princípio de Inversão de Dependência é diferente do princípio "Programa para uma interface, não uma implementação".

Eu li sobre o DIP em vários lugares da web e isso não esclareceu minha confusão. Ainda não vejo como os dois princípios diferem um do outro. Obrigado pela ajuda.

Aviv Cohn
fonte

Respostas:

25

"Programar em uma interface" significa que não depende de um tipo concreto para fazer seu trabalho , mas não especifica como você deve obter sua dependência.

O "Princípio da inversão de dependência" diz que um objeto não deve controlar a criação de suas dependências, deve apenas anunciar de que dependência ele precisa e deixar que o chamador o forneça . Mas não especifica se a dependência deve ser um tipo concreto ou uma interface.

Ilustrarei as diferenças com algum código C #.

O exemplo a seguir depende de um tipo concreto e controla a criação da própria dependência. Segue-se nem "programa para uma interface" nem "inversão de dependência":

public class ThingProcessor
{
    MyThing _myThing;

    public ThingProcessor()
    {
        _myThing = new MyThing();
    }

    public void DoSomething()
    {
        _myThing.DoIt();
    }
}

O exemplo a seguir depende de uma interface, mas controla a criação da própria dependência. Segue "programa para uma interface", mas não "inversão de dependência":

public class ThingProcessor
{
    IMyThing _myThing;

    public ThingProcessor()
    {
        _myThing = ThingFactory.GiveMeANewMyThing();
    }

    public void DoSomething()
    {
        _myThing.DoIt();
    }
}

O exemplo a seguir depende de um tipo concreto, mas solicita que sua dependência seja criada e passada para ele. Segue "inversão de dependência", mas não "programa para uma interface":

public class ThingProcessor
{
    MyThing _myThing;

    public ThingProcessor(MyThing myThing)
    {
        _myThing = myThing;
    }

    public void DoSomething()
    {
        _myThing.DoIt();
    }
}

O exemplo a seguir depende de uma interface e solicita que sua dependência seja criada e passada para ela. Segue "inversão de dependência" e "programa para uma interface":

public class ThingProcessor
{
    IMyThing _myThing;

    public ThingProcessor(IMyThing myThing) // using an interface
    {
        _myThing = myThing;
    }

    public void DoSomething()
    {
        _myThing.DoIt();
    }
}
Eric King
fonte
1
Excelente ilustração da diferença.
Rory Hunter
8
O que você está falando é sobre a injeção dependente. E inversão de dependência e injeção de dependência são duas coisas diferentes.
eufórico
1
@Euphoric Estou falando do Princípio da Inversão da Dependência, que é um conceito abstrato, usando a Injeção de Dependência como exemplo concreto de implementação. Eu entendo a diferença.
Eric Rei
1
@EricKing Então você deve dizer explicitamente que, em sua resposta, em vez de "O" Princípio da inversão de dependência "diz ...", o que obviamente está errado se você ler minha resposta.
eufórico
1
Eu concordo com eufórico. O Princípio da Inversão da Dependência diz que as camadas de código de nível superior devem depender de partes de código de nível inferior, e não vice-versa. Por exemplo, PrintStreamdeve depender da interface estabelecida por ByteOutputStream. A injeção de dependência não menciona nada sobre quem deve depender de quem.
Doval
5

Eles são geralmente a mesma coisa. Se você ler O que é o Princípio da inversão de dependência e por que é importante? e princípio de inversão de dependência , você perceberá que os dois "princípios" falam basicamente da mesma coisa.

  • Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações.
  • Abstrações nunca devem depender de detalhes. Os detalhes devem depender de abstrações.

Interface é uma abstração e implementação é um detalhe. Se você substituí-los nas duas instruções anteriores, obtém basicamente "o código deve depender de interfaces e não de implementações". E isso soa como a mesma coisa para mim.

Eufórico
fonte
Esta deve ser a resposta aceita, a outra resposta mais votada é enganosa
Sameh Deabes
2

As interfaces são uma maneira de implementar o DI. Se você especificar uma interface como parâmetro no método construtor de uma classe, poderá entregar qualquer objeto que desejar ao método construtor, desde que esse objeto implemente a interface do parâmetro construtor.

Em outras palavras, programar uma interface permite alterar a implementação dessa interface. É assim que podemos substituir objetos reais por objetos reais durante o teste de unidade, especificar diferentes provedores de dados e assim por diante.

Robert Harvey
fonte