Princípio da inversão de dependência

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:[1]

  1. Módulos de alto nível não devem incorporar (ou incluir) nada dos módulos de baixo nível. Ambos devem trabalhar apenas com abstrações, ou seja, interfaces.
  2. Abstrações não devem depender de detalhes de implementação, mas os detalhes é que devem depender de abstrações.

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.[2]

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 editar

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.

 

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 editar

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.

 

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 editar

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:

  1. É 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".
  2. 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:

  1. 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.
  2. 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.
  3. 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.
  4. Interface de generalização também restringe o uso de uma linguagem de programação.

Generalização restrições editar

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 editar

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 editar

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 editar

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.

 

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:

 

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 editar

Genealógicas módulo editar

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 editar

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:

  1. A conexão/Desconexão (uma conexão de camada de persistência pode ser necessária)
  2. Pasta/criação de tags/renomear/apagar/listar interface
  3. Criação do arquivo/substituição/renomear/apagar/interface de leitura
  4. Procurar arquivo
  5. Simultâneas de substituição ou excluir resolução
  6. 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.

Ao projetar o servidor de arquivo remoto de cliente para cada conceitual da interface, você tem que perguntar a si mesmo o nível de serviço de seu alto nível de módulos de exigir (não é necessário todos eles) e não apenas como implementar o servidor de arquivo remoto funcionalidades, mas talvez como fazer os serviços de arquivo em seu aplicativo compatível entre já implementados serviços de arquivo (arquivos locais, existentes em nuvem clientes) e o seu novo servidor de arquivos remoto do cliente.

Depois de ter desenhado o resumo interfaces necessárias, o seu servidor de arquivos remoto cliente deve implementar estas interfaces. E porque você provavelmente restrito em alguns locais funcionalidades existentes em locais de arquivo (por exemplo, atualização de arquivo), você pode ter que escrever adaptadores para locais ou outras existentes usado acesso remoto a arquivos módulos, cada um oferecendo o mesmo resumo interfaces. Você também tem que escrever o seu próprio arquivo de acesso enumerador permitindo recuperar de arquivo todos os sistemas compatíveis com o disponível e configurado em seu computador.

Uma vez que você fizer isso, seu aplicativo será capaz de salvar seus documentos localmente ou remotamente, de forma transparente. Ou mais simples, o alto nível de módulo usando o novo arquivo interfaces de acesso podem ser usados indistintamente no local ou acesso remoto a arquivos cenários, tornando-reutilizáveis.

Comentário : muitos sistemas Operacionais começaram a implementar este tipo de funcionalidades e seu trabalho pode ser limitado para se adaptar a sua nova cliente, para isso já abstraídos modelos.

Neste exemplo, o pensamento do módulo como um conjunto de interfaces abstratas, e a adaptação de outros módulos para este conjunto de interfaces, permite que você para fornecer uma interface comum para muitos sistemas de armazenamento.

Model View Controller editar

 
Exemplo de MERGULHO

A INTERFACE do usuário e ApplicationLayer pacotes contém principalmente classes concretas. Controladores contém resumos/tipos de interface. UI tem uma instância de ICustomerHandler. Todos os pacotes são separados fisicamente. No ApplicationLayer há uma implementação concreta de que a Página classe vai usar. Instâncias desta interface são criados dinamicamente por uma Fábrica (possivelmente no mesmo Controladores de pacote). O concreto tipos de Página e CustomerHandler, não dependem uns dos outros; ambos dependem ICustomerHandler.

O efeito direto é que a INTERFACE do usuário não precisa fazer referência a ApplicationLayer ou qualquer de concreto pacote que implementa o ICustomerHandler. A classe do betão será carregado usando reflexão. A qualquer momento, a implementação concreta poderia ser substituído por outro de concreto de implementação sem alterar a INTERFACE do usuário de classe. Outra possibilidade interessante é que a Página de classe implementa uma interface IPageViewer que pode ser passado como um argumento para ICustomerHandler métodos. Em seguida, a implementação concreta pode se comunicar com a INTERFACE do usuário sem uma concreta de dependência. Novamente, ambos estão ligados pelas interfaces.

Padrões relacionados editar

Aplicando a inversão de dependência princípio também pode ser visto como um exemplo de placa padrão, por exemplo, o alto nível de classe define a sua própria interface de adaptador que é a abstração que o alto nível de classes dependem. O adaptee implementação depende também da placa de interface de abstração (claro, desde que ele implementa a sua interface), enquanto ele pode ser implementado utilizando o código de dentro de sua própria baixo nível de módulo. O alto nível não tem dependência do baixo nível de módulo, pois utiliza apenas o baixo nível indiretamente através da placa de interface de invocação de métodos polimórficos para a interface, que são implementadas pelo adaptee e seu baixo nível de módulo.

Vários padrões, tais como Plugin, Service Locator, ou Injeção de Dependência são empregadas para facilitar o tempo de execução de provisionamento dos escolhidos de baixo nível de componente de implementação para o alto nível de componente.

História editar

A dependência inversão de princípio foi postulada por Robert C. Martin e descrito em várias publicações, incluindo o papel Orientado a Objeto-Design de Métricas de Qualidade: uma análise de dependências, um artigo publicado em C++ Relatório em Maio de 1996, o direito de Dependência, de Inversão de Princípio, e os livros Ágeis de Desenvolvimento de Software, Princípios, Padrões e Práticas, e Princípios Ágeis, Padrões e Práticas em C#.

Ver também editar

Referências editar

  1. Martin, Robert C. (2003). Agile Software Development, Principles, Patterns, and Practices. [S.l.]: Prentice Hall. pp. 127–131. ISBN 978-0135974445 
  2. Freeman, Eric; Freeman, Elisabeth; Kathy, Sierra; Bert, Bates (2004). Hendrickson, Mike; Loukides, Mike, eds. «Head First Design Patterns» (paperback). O'REILLY. 1. ISBN 978-0-596-00712-6. Consultado em 21 de junho de 2012 

Ligações externas editar