Qual é o sentido de ter todas as classes de serviço com uma interface? [duplicado]

84

Na empresa em que trabalho, todas as classes de serviço têm uma interface correspondente. Isso é necessariamente? A maioria dessas interfaces é usada apenas por uma única classe e não estamos criando nenhum tipo de API pública. Com modernas bibliotecas de zombaria capazes de zombar de classes concretas e IDEs capazes de extrair uma interface de uma classe com dois ou mais cliques, isso é apenas um remanescente dos tempos antigos?

    
por Bob Roberts 24.05.2012 / 17:53
fonte

6 respostas

79

Sua empresa está seguindo os princípios do SOLID e direcionando uma interface em vez de uma classe concreta que adiciona zero de sobrecarga ao programa. O que eles estão fazendo é uma quantidade muito moderada de trabalho extra que pode pagar os volumes quando as suposições que você está fazendo acabam sendo falsas ... e você nunca pode dizer qual suposição será. O que você está recomendando enquanto trabalha um pouco menos, pode custar muitas, muitas, muitas horas de refatoração que poderiam ter sido feitas antes do tempo simplesmente seguindo os princípios básicos de design OO.

Você deveria aprender com esses caras e se considerar sortudo. Queria ter trabalhado em um ambiente onde o design sólido era uma meta prioritária.

    
por 24.05.2012 / 17:59
fonte
66

Dada a sua pergunta, presumo que as razões para esse tipo de design não estejam documentadas.

O uso injustificado de uma interface com implementação única é totalmente errado, pois isso viola YAGNI . Na minha experiência, isso também tem sido muito prejudicial à manutenção, principalmente porque os métodos que implementam a interface são forçados a ser desnecessariamente públicos. Depois de reunir mais experiência com a refatoração, provavelmente você aprenderá a apreciar o charme modesto de > private e pacotes private modificadores de acesso, permitindo focalizar a atenção em uma única classe / pacote.

Quanto ao uso justificado indocumentado deste idioma, é a meu ver tão ruim - em primeiro lugar, porque não permite que um mantenedor "conte o bem do mal". Como resultado, isso deixa entre opções não muito atraentes. As opções são: ou você mantém as coisas públicas questionáveis no estado em que se encontra, assim reduzindo a produtividade toda vez que precisar alterar o código ou fazendo alterações arriscadas ao "colapsar" cegamente a implementação única para facilitar para manter POJO - expor a si mesmo ao risco de descobrir dolorosamente que isso é errado, que algum outro (Deus me livre, remoto ) módulo fora de sua vista espera a interface.

Eu tenho passado por "revelações" causadas pelo colapso errado da interface de implementação única algumas vezes. Cada vez que tem sido uma experiência bastante educativa, mas eu realmente não quero chegar lá novamente. O fato é que isso acontece nos testes finais, na integração ou até mesmo na aceitação do usuário, e a reversão / correção do erro cometido há muito tempo neste estágio é bastante incômoda.

  • Uma opção que não deve ser deixada sem mencionar é investigar se o uso indocumentado é justificado (e, depois disso, recolhido ou documentado, respectivamente) exatamente no momento em que você o encontra.

    Para mim, este foi bastante contraproducente. Essa abordagem essencialmente força a pessoa a fazer o teste de integração de rodada completa, que é provavelmente uma das maneiras mais eficientes de quebrar um fluxo no meio de alguma correção / refatoração complicada.

I just couldn't see the practicality... the interfaces are used one-to-one like com.company.service.foo and com.company.service.foo.impl

Bem abaixo é sobre como eu normalmente lide com casos como esse.

  1. Crie um tíquete no issue tracker , como " PRJ-123 não documentado uso questionável de interface com implementação única em Foo / FooImpl ".
    Adicionar a descrição do ticket ou comentar uma explicação de que isso prejudica a manutenção e ressaltar que sem documentação isso parece overengineering . Adicione um comentário sugerindo para corrigir o problema "colapsando" isso em um POJO, para facilitar a manutenção.
  2. Espere por algum tempo para o caso de alguém explicar algo. eu esperaria uma ou duas semanas pelo menos

    • Se alguém explicar o propósito, a) colocar isso no ticket, b) adicionar ao Foo javadocs algo como finalidade da interface explicada no ticket PRJ-123 , c) fechar o ticket, d) pule os próximos três passos.
    • Caso contrário, ...
  3. Venha ao líder ou gerente da equipe para perguntar o que eles pensariam se eu consertar o tíquete como sugerido.
    Escolha um conselheiro com autoridade suficiente para suportar o "teste de grito" no caso de correção sugerida ser errada .
  4. Recolha para POJO de acordo com a sugestão de correção, organize revisão de código se isso for possível (em casos escorregadios como esse não vai doer para cobrir as costas).
  5. Aguarde até que a alteração passe no teste completo e atualize o ticket, dependendo de seu resultado - adicione as informações sobre se a alteração passou no teste ou não.
  6. Crie e gerencie um novo ticket do rastreador de problemas para lidar com casos semelhantes restantes com base no resultado de seu ticket piloto ( PRJ-123 ): documente a finalidade ou reduza para POJO.

    
por 24.05.2012 / 23:18
fonte
31

Veja como Adam Bien pense sobre essa questão: Serviço s = new ServiceImpl () - Por que você está fazendo isso?

That is not only bloat (and the opposite of "Convention Over Configuration" idea), but it causes real damage:

  1. Imagine you get another implementation (thats the whole point of an interface) - how would you name it?
  2. It doubles the amount of artifacts - and significantly increases the "complexity"
  3. It is really funny to read the javadocs on the interface and the impl - another redundancy
  4. The navigation in the IDE is less fluent

e eu concordo com ele.

Talvez seus colegas de trabalho ainda estejam presos no tempo com o J2EE, porque isso era necessário ao trabalhar com o J2EE, talvez você possa encontrar na internet antigos tutoriais sobre tempos difíceis no J2EE.

    
por 03.09.2012 / 19:08
fonte
17

As interfaces Java não são apenas sobre falsificação (embora, é claro, isso seja um fator). Uma interface expõe um contrato público para o seu serviço, sem detalhes de implementação, como métodos ou atributos privados.

Observe que "público" ao usar serviços internos (como no seu caso) se refere aos usuários reais de tais serviços, incluindo - mas não se limitando a - outros programadores e serviços internos!

    
por 24.05.2012 / 18:11
fonte
10

Uma possível razão para cada classe de serviço ter uma interface é que ela torna as interações com estruturas sofisticadas (por exemplo, Spring, JEE) muito mais simples. Isso ocorre porque o Java pode simplesmente gerar objetos interceptores contra interfaces (consulte java.lang.reflect.Proxy ); Fazê-lo contra classes concretas é muito mais complicado e preenchido com algumas advertências não óbvias quando se trabalha com vários classloaders diferentes. Isso vale duplamente se você trabalhar com OSGi, onde essas interfaces de serviço serão carregadas de um carregador de classe diferente das implementações desses serviços. Isso (juntamente com a malha de descoberta de serviço), por sua vez, impõe uma separação muito strong entre cada serviço e seus clientes; os clientes literalmente não podem quebrar a abstração.

Lembre-se de que, mesmo que um IDE possa extrair uma interface de uma classe com um único clique, isso não significa necessariamente que ela extrairá a interface correta . Inteligência ainda é necessária.

    
por 26.05.2012 / 16:39
fonte
0

Parece que a sobrecarga para usar a interface inicialmente .. mas mais tarde, quando precisamos estender algumas funcionalidades essas interfaces ajudam muito.

Se você fizer apenas uma implementação concreta, você terá que mudar muito a implementação do código. Mas usando a interface você precisa adicionar uma nova classe que implementa o contrato da Interface (e você pode chamar new class da variável de referência Interface antiga).

    
por 26.05.2012 / 11:28
fonte