No paradigma de orientação a objetos, o Princípio da inversão de dependência refere-se a uma forma específica de desacoplamento de módulos de software que determina a inversão das relações de dependência: partem de módulos de alto nível, responsáveis pelas diretrizes, para os de baixo nível. Assim, os módulos de alto nível tornam-se independentes dos detalhes de implementação dos de baixo nível. O princípio estabelece que:
Ao definir que os objetos de alto e baixo nível devem fundamentar-se nas mesmas abstrações, este princípio de projeto inverte a maneira como as pessoas geralmente raciocinam dentro do paradigma de orientação a objetos.
A ideia que está por trás dos itens A e B é que, no projeto de integração de módulos de alto e baixo nível, a sua interação deve ser feita de forma abstrata. Este princípio não acarreta consequências apenas no desenvolvimento dos módulos de alto nível, mas também nos de baixo nível, que precisam ser produzidos com a noção de interação e de possibilidade de mudança na interface de uso.
Muitas vezes, quando se pensa na interação como um conceito abstrato, é possível reduzir o acoplamento dos componentes sem introduzir novos padrões de código, o que torna o modelo de interação mais leve e menos dependente de implementação.
Padrão de camadas tradicional No convencional, a arquitetura de aplicativos, componentes de nível inferior (por exemplo, Utilitário Camada) são projetados para ser consumido pelo maior nível de componentes (e.g. Política de Camada) que permitem que sistemas cada vez mais complexos para ser construído. Nesta composição, o maior nível de componentes dependem diretamente em componentes de nível inferior para conseguir alguma tarefa. Esta dependência de componentes de nível inferior limita as oportunidades de reutilização de componentes superiores. centro O objetivo da inversão de dependência padrão é para evitar este altamente juntamente distribuição com a mediação de um resumo camada, e aumentar a reutilização de maior/política de camadas.
Dependência de inversão de padrão Com a adição de uma camada abstrata, ambos de alto e de baixo nível camadas reduzir o tradicional dependências de cima para baixo. No entanto, a "inversão" conceito não significa que de nível inferior camadas dependem, em maior nível de camadas. Ambas as camadas devem depender de abstrações que desenhar o comportamento necessários de nível superior camadas. centro Em uma aplicação direta da inversão de dependência, os resumos são de propriedade do superior/política de camadas. Este grupos de arquitectura superior/política de componentes e as abstrações que definem inferior serviços junto no mesmo pacote. O nível inferior camadas são criadas por herança/implementação destas classes abstratas ou interfaces.
A inversão de dependências e de propriedade incentiva a reutilização de superior/política de camadas. Camadas superiores pode usar outras implementações do menor de serviços. Quando o nível inferior da camada de componentes são fechados ou quando a aplicação requer a reutilização de serviços existentes, é comum que um Adaptador de mediação entre os serviços e as abstrações.
Dependência de inversão de padrão de generalização Em muitos projetos a dependência inversão de princípio e padrão são considerados como um único conceito que deve ser generalizada. Há pelo menos duas razões para isso:
É mais simples para ver um bom pensamento, a princípio, como um padrão de codificação. Uma vez que uma classe abstrata ou uma interface tem sido codificadas, o programador pode dizer: "eu tenho feito o trabalho de abstração". Porque muitos testes de unidade ferramentas dependem de herança para realizar o escárnio, o uso de interfaces genéricas entre classes (não só entre os módulos quando faz sentido para usar na generalidade) se tornou a regra.
Se a zombaria ferramenta utilizada depende somente da herança, a generalização da dependência inversão de padrão pode tornar-se uma necessidade. Isso tem grandes inconvenientes:
Simplesmente implementando uma interface mais de uma classe não é suficiente e, geralmente, não reduzir o acoplamento, apenas pensando sobre o potencial de captação de interações podem levar a um menor juntamente design. A implementação de interfaces genéricas em qualquer lugar em um projeto torna, de longe, mais difícil de entender e manter. Em cada etapa, o leitor poderá perguntar a si mesmo quais são as outras implementações dessa interface e a resposta geralmente é: apenas zombam. A interface de generalização requer mais do encanamento do código, em especial as fábricas que geralmente dependem de uma dependência de injeção de quadro. Interface de generalização também restringe o uso de uma linguagem de programação.
Generalização restrições A presença de interfaces para realizar a Inversão de Dependência Padrão (DIP) ter outras implicações de design em um objeto-programação orientada por:
Todas as variáveis de membro em uma classe deve ser interfaces ou resumos. Todos os betão de classe de pacotes deve conectar somente através de interface ou classe abstrata pacotes. Nenhuma classe deve derivar de uma classe concreta. Nenhum método deve substituir um método implementado. Todos variável de instância que requer a implementação de um creational padrão , tais como o método de fábrica ou a fábrica padrão, ou o uso de uma dependência de injeção de quadro.
Interface zombando restrições Usando herança baseada em zombando de ferramentas também introduzir restrições:
Estática visível externamente os membros devem, sistematicamente, dependem da injeção de dependência, tornando-os muito mais difícil de implementar. Todos os testável métodos deve tornar-se uma implementação de interface ou uma substituição de uma definição abstrata.
Direções futuras Princípios são as formas de pensar, os padrões são comuns formas de resolver problemas. Padrões de codificação pode ser visto como falta de recursos das linguagens de programação.
Linguagens de programação continuará a evoluir para permitir a impor mais forte e mais preciso o uso de contratos, em pelo menos duas direções: cumprimento de condições de uso (pré-, pós - e invariável condições), e estado baseado em interfaces. Este será, provavelmente, incentivar e, potencialmente, de simplificar o mais forte aplicação da inversão de dependência padrão em muitas situações. Mais e mais zombando de ferramentas a usar a injeção de código para resolver o problema da substituição estático e não membros virtuais. Linguagem de programação, provavelmente, irá evoluir para gerar o escárnio compatível com o de bytecode. One direction vai ser para restringir o uso do não virtual membros, e o outro será para gerar, pelo menos em situações de teste, um bytecode permitir que não-herança com base zombando.
Implementações As duas implementações de MERGULHO uso de arquitetura lógica semelhante, com diferentes implicações.
Um direto de pacotes de implementação da política de classes com serviço de resumos de aulas em uma biblioteca. Neste implementação de alto nível de componentes e componentes de baixo nível são distribuídos em pacotes separados, bibliotecas, onde as interfaces definem o comportamento/serviços exigidos pelo alto nível de componente são de propriedade, e existem dentro o alto nível do componente de biblioteca. A implementação de alto nível da componente de interface com o baixo nível de componente requer que o baixo nível de pacote de componente dependem do alto nível de componente para a compilação, portanto, a inversão convencional de relação de dependência. centro Figuras 1 e 2 ilustram o código com a mesma funcionalidade, no entanto, na Figura 2, uma interface tem sido utilizada para inverter a dependência. A direção de dependência pode ser escolhido de forma a maximizar a política de reutilização de código, e eliminar dependências cíclicas.
Nesta versão do DIP, a camada inferior do componente de dependência nas interfaces/resumos em nível superior camadas faz re-utilização da camada inferior componentes difícil. Esta implementação, em vez disso, "inverte" a tradicional dependência de cima para baixo, para a frente, de baixo para cima.
Uma solução mais flexível extrai o resumo de componentes em um conjunto independente de pacotes/bibliotecas: centro A separação de todas as camadas em seu próprio pacote incentiva a re-utilização de qualquer camada, fornecendo robustez e mobilidade.
Exemplos
Genealógicas módulo Um genealógica sistema poderá representar o relacionamento entre as pessoas, como um gráfico de primeiro nível relacionamentos entre eles (pai/filho, pai/filha, mãe/filho, mãe/filha, marido/mulher, mulher/marido...). Isso é muito eficiente (e extensível: ex-marido/ex-mulher, o responsável legal...)
Mas o alto nível de módulos pode exigir uma maneira mais simples de procurar o sistema: uma pessoa pode ter filhos, um pai, uma mãe, irmãos e irmãs (incluindo, ou não, meio-irmãos e irmãs), avôs, avós, tios, tias, primos, primas ...
Dependendo do uso do genealógica módulo, apresentando comuns relações distintas direto propriedades (escondendo o gráfico) vai fazer a ligação entre o alto nível do módulo e genealógico módulo por muito mais leves e permitem alterar a representação interna completamente sem qualquer efeito sobre o uso de módulos. Ele também permite incorporar na genealógica módulo a definição exata do irmão e irmãs (incluindo ou não pela metade), tios ... permitindo que se possa impor o único princípio de responsabilidade.
Finalmente, se o primeiro extensível generalizada gráfico abordagem parece mais extensível, o uso do genealógica módulo pode mostrar que um mais especializado e mais simples relação de implementação é suficiente para o aplicativo(s) e ajuda você a fazer um sistema mais eficiente.
Neste exemplo abstraindo a interação entre os módulos leva a uma simplificada interface de baixo-nível de módulo e pode levar a uma execução mais simples.
Servidor de arquivos remoto cliente Imagine que você tem para a implementação de um cliente para um servidor de arquivos remoto (FTP, armazenamento na nuvem ...). Você pode pensar nisso como um conjunto de interfaces abstratas:
A conexão/Desconexão (uma conexão de camada de persistência pode ser necessária) Pasta/criação de tags/renomear/apagar/listar interface Criação do arquivo/substituição/renomear/apagar/interface de leitura Procurar arquivo Simultâneas de substituição ou excluir resolução Arquivo histórico de gestão ...
Se ambos os arquivos locais e arquivos remotos oferece o mesmo resumo interfaces de alto nível de módulo, usando arquivos locais e implementar totalmente a dependência de inversão de padrão será capaz de acessar arquivos locais e remotos de forma indiscriminada.
Disco Local geralmente usam pasta de armazenamento remoto pode usar pasta e/ou tags. Você tem que decidir como unificar-las, se possível.
No arquivo remoto podemos apenas criar ou substituir: remota de arquivos de atualização não necessariamente faz sentido, porque aleatória de atualização é muito lenta comparando local de arquivo aleatório de atualização e podem ser muito complicadas de implementar). No arquivo remoto podemos precisar parcial ler e escrever (pelo menos dentro do arquivo remoto módulo para permitir o download ou upload de continuar depois de uma interrupção de uma comunicação), mas de leitura aleatória não é adaptado (exceto se um cache local é usado).
Pesquisa de ficheiros pode ser conectável : pesquisa de ficheiros podem confiar no sistema operacional ou em particular, de marca ou de pesquisa de texto completo, a ser implementado com sistemas distintos (OS incorporados, ou disponível separadamente).
Simultâneas de substituição ou excluir resolução de detecção pode afetar o outro abstrato interfaces.