Já vi isso mencionado algumas vezes e não sei ao certo o que isso significa. Quando e por que você faria isso?
Eu sei o que as interfaces fazem, mas o fato de eu não estar claro sobre isso me faz pensar que estou perdendo o uso delas.
Será que você deveria fazer:
IInterface classRef = new ObjectWhatever()
Você poderia usar qualquer classe que implementa IInterface
? Quando você precisaria fazer isso? A única coisa em que consigo pensar é se você tem um método e não tem certeza de qual objeto será passado, exceto pela implementação IInterface
. Não consigo pensar quantas vezes você precisaria fazer isso.
Além disso, como você pode escrever um método que utiliza um objeto que implementa uma interface? Isso é possível?
language-agnostic
oop
interface
Damien
fonte
fonte
Respostas:
Há aqui algumas respostas maravilhosas para essas perguntas que abordam todos os tipos de detalhes sobre interfaces e código de acoplamento fraco, inversão de controle e assim por diante. Há algumas discussões bastante inebriantes, então eu gostaria de aproveitar um pouco as coisas para entender por que uma interface é útil.
Quando comecei a me expor a interfaces, eu também fiquei confuso sobre a relevância delas. Não entendi por que você precisava deles. Se estamos usando uma linguagem como Java ou C #, já temos herança e eu via as interfaces como uma forma mais fraca de herança e pensamento: "por que se preocupar?" Em certo sentido, eu estava certo, você pode pensar em interfaces como uma espécie de forma fraca de herança, mas além disso, finalmente entendi seu uso como uma construção de linguagem, pensando nelas como um meio de classificar traços ou comportamentos comuns exibidos por potencialmente muitas classes de objetos não relacionados.
Por exemplo - digamos que você tenha um jogo SIM e tenha as seguintes classes:
Claramente, esses dois objetos não têm nada em comum em termos de herança direta. Mas, você poderia dizer que ambos são irritantes.
Digamos que nosso jogo precise ter algum tipo de coisa aleatória que incomode o jogador quando ele janta. Pode ser um
HouseFly
ou umTelemarketer
ou ambos - mas como você permite os dois com uma única função? E como você pede a cada tipo diferente de objeto para "fazer sua coisa irritante" da mesma maneira?A chave para perceber é que tanto um
Telemarketer
eHouseFly
compartilham um comum vagamente interpretado comportamento, mesmo que eles não são nada parecidos em termos de modelagem-los. Então, vamos criar uma interface que ambos possam implementar:Agora temos duas classes que podem ser irritantes à sua maneira. E eles não precisam derivar da mesma classe base e compartilhar características inerentes comuns - eles simplesmente precisam satisfazer o contrato
IPest
- esse contrato é simples. Você apenas precisaBeAnnoying
. Nesse sentido, podemos modelar o seguinte:Aqui, temos uma sala de jantar que aceita vários comensais e várias pragas - observe o uso da interface. Isso significa que, em nosso pequeno mundo, um membro da
pests
matriz pode realmente ser umTelemarketer
objeto ou umHouseFly
objeto.O
ServeDinner
método é chamado quando o jantar é servido e nosso pessoal na sala de jantar deve comer. Em nosso pequeno jogo, é quando nossas pragas fazem seu trabalho - cada praga é instruída a ser irritante por meio daIPest
interface. Dessa forma, podemos facilmente ter os doisTelemarketers
eHouseFlys
ser irritante em cada um de seus modos - nos preocupamos apenas com o fato de termos algo noDiningRoom
objeto que é uma praga, na verdade não nos importamos com o que é e eles não podem ter nada a ver. comum com outro.Este exemplo pseudo-código muito elaborado (que se arrastou muito mais do que eu previa) serve apenas para ilustrar o tipo de coisa que finalmente acendeu a luz para mim em termos de quando poderíamos usar uma interface. Peço desculpas antecipadamente pela tolice do exemplo, mas espero que ajude na sua compreensão. E, com certeza, as outras respostas postadas que você recebeu aqui realmente cobrem toda a gama de uso de interfaces hoje em dia em padrões de design e metodologias de desenvolvimento.
fonte
BeAnnoying
como não operacionais; essa interface pode existir no lugar ou além da interface para coisas que são irritantes (se ambas as interfaces existirem, a interface "coisas que são irritantes" deve herdar da interface "coisas que podem ser irritantes"). A desvantagem de usar essas interfaces é que as implementações podem ficar sobrecarregadas com a implementação de um número "irritante" de métodos de stub. A vantagem é que ...IPest[]
referências IPest, você pode chamarBeAnnoying()
porque eles têm esse método, enquanto você não pode chamar outros métodos sem uma conversão. No entanto, cada objeto individualBeAnnoying()
método será chamado.O exemplo específico que eu costumava dar aos alunos é que eles deveriam escrever
ao invés de
Eles parecem exatamente iguais em um programa curto, mas se você continuar usando
myList
100 vezes no programa, poderá começar a ver a diferença. A primeira declaração garante que você chame apenas métodosmyList
definidos pelaList
interface (portanto, nenhumArrayList
método específico). Se você programou a interface dessa maneira, mais tarde poderá decidir que realmente precisae você só precisa alterar seu código nesse local. Você já sabe que o restante do seu código não faz nada que será quebrado alterando a implementação porque você programou para a interface .
Os benefícios são ainda mais óbvios (eu acho) quando você está falando sobre parâmetros de método e valores de retorno. Veja isso por exemplo:
Essa declaração de método vincula você a duas implementações concretas (
ArrayList
eHashMap
). Assim que esse método é chamado a partir de outro código, qualquer alteração nesses tipos provavelmente significa que você também precisará alterar o código de chamada. Seria melhor programar para as interfaces.Agora, não importa que tipo de
List
retorno você retorne ou comoMap
é transmitido como parâmetro. As alterações feitas dentro dodoSomething
método não forçarão a alteração do código de chamada.fonte
Programar em uma interface está dizendo: "Eu preciso dessa funcionalidade e não me importo de onde ela vem".
Considere (em Java), a
List
interface versus as classesArrayList
eLinkedList
concretas. Se tudo o que me interessa é o fato de ter uma estrutura de dados que contém vários itens de dados que devo acessar por meio de iteração, eu selecionaria umList
(e isso é 99% do tempo). Se eu souber que preciso inserir / excluir em tempo constante em qualquer extremidade da lista, posso escolher aLinkedList
implementação concreta (ou, mais provavelmente, usar a interface Queue ). Se eu sei que preciso de acesso aleatório por índice, eu escolho aArrayList
classe concreta.fonte
O uso de interfaces é um fator-chave para tornar seu código facilmente testável, além de remover acoplamentos desnecessários entre suas classes. Ao criar uma interface que define as operações em sua classe, você permite que as classes que desejam usar essa funcionalidade possam utilizá-la sem depender diretamente da classe de implementação. Se, posteriormente, você decidir alterar e usar uma implementação diferente, precisará alterar apenas a parte do código em que a implementação é instanciada. O restante do código não precisa ser alterado porque depende da interface, não da classe de implementação.
Isso é muito útil na criação de testes de unidade. Na classe em teste, você depende da interface e injeta uma instância da interface na classe (ou uma fábrica que permita criar instâncias da interface conforme necessário) por meio do construtor ou de um configurador de propriedades. A classe usa a interface fornecida (ou criada) em seus métodos. Ao escrever seus testes, você pode simular ou falsificar a interface e fornecer uma interface que responda com os dados configurados no seu teste de unidade. Você pode fazer isso porque sua classe em teste lida apenas com a interface, não com sua implementação concreta. Qualquer classe que implemente a interface, incluindo sua classe simulada ou falsa, fará isso.
Edição: Abaixo está um link para um artigo onde Erich Gamma discute sua citação, "Programa para uma interface, não uma implementação".
http://www.artima.com/lejava/articles/designprinciples.html
fonte
A programação para uma interface não tem absolutamente nada a ver com interfaces abstratas, como vemos em Java ou .NET. Nem sequer é um conceito de POO.
O que isso significa é não mexer com as partes internas de um objeto ou estrutura de dados. Use a Interface do programa abstrata, ou API, para interagir com seus dados. Em Java ou C #, isso significa usar propriedades e métodos públicos em vez do acesso ao campo bruto. Para C, isso significa usar funções em vez de ponteiros brutos.
EDIT: E com bancos de dados, significa usar visualizações e procedimentos armazenados em vez de acesso direto à tabela.
fonte
Você deve analisar a Inversão de controle:
Nesse cenário, você não escreveria isso:
Você escreveria algo como isto:
Isso entraria em uma configuração baseada em regras no
container
objeto e construiria o objeto real para você, que poderia ser ObjectWhatever. O importante é que você poderia substituir essa regra por algo que usasse outro tipo de objeto, e seu código ainda funcionaria.Se deixarmos a IoC fora da mesa, você poderá escrever um código que saiba que pode falar com um objeto que faz algo específico , mas não com qual tipo de objeto ou como ele o faz.
Isso seria útil ao passar parâmetros.
Quanto à sua pergunta entre parênteses "Além disso, como você pode escrever um método que utiliza um objeto que implementa uma Interface? Isso é possível?", Em C # você simplesmente usava o tipo de interface para o tipo de parâmetro, assim:
Isso se conecta diretamente à "conversa com um objeto que faz algo específico". O método definido acima sabe o que esperar do objeto, que implementa tudo na interface II, mas não se importa com o tipo de objeto, apenas com o cumprimento do contrato, o que é uma interface.
Por exemplo, você provavelmente está familiarizado com calculadoras e provavelmente usou algumas em seus dias, mas na maioria das vezes elas são todas diferentes. Você, por outro lado, sabe como uma calculadora padrão deve funcionar, para poder usá-las todas, mesmo que não possa usar os recursos específicos que cada calculadora possui e que nenhum outro possui.
Essa é a beleza das interfaces. Você pode escrever um pedaço de código, que saiba que ele passará objetos para os quais pode esperar um determinado comportamento. Não importa que tipo de objeto seja, apenas que apóia o comportamento necessário.
Deixe-me dar um exemplo concreto.
Temos um sistema de tradução personalizado para formulários do Windows. Esse sistema percorre os controles em um formulário e traduz o texto em cada um. O sistema sabe como lidar com controles básicos, como o tipo de controle que possui uma propriedade de texto e itens básicos semelhantes, mas, para qualquer coisa básica, fica aquém.
Agora, como os controles herdam de classes predefinidas sobre as quais não temos controle, podemos fazer uma de três coisas:
Então fizemos o nr. 3. Todos os nossos controles implementam ILocalizable, que é uma interface que nos dá um método, a capacidade de traduzir "a si próprio" em um contêiner de regras / textos de tradução. Como tal, o formulário não precisa saber que tipo de controle encontrou, apenas que implementa a interface específica e sabe que existe um método no qual ele pode chamar para localizar o controle.
fonte
Código para a interface A implementação não tem nada a ver com Java, nem sua construção de interface.
Esse conceito foi destacado nos livros Patterns / Gang of Four, mas provavelmente já existia muito antes disso. O conceito certamente existia muito antes de o Java existir.
A construção da interface Java foi criada para ajudar nessa idéia (entre outras coisas), e as pessoas se concentraram demais na construção como o centro do significado e não a intenção original. No entanto, é por isso que temos métodos e atributos públicos e privados em Java, C ++, C #, etc.
Significa apenas interagir com um objeto ou interface pública do sistema. Não se preocupe ou até preveja como ele faz o que faz internamente. Não se preocupe sobre como é implementado. No código orientado a objetos, é por isso que temos métodos / atributos públicos versus privados. Nosso objetivo é usar os métodos públicos porque os métodos privados existem apenas para uso interno, dentro da classe. Eles compõem a implementação da classe e podem ser alterados conforme necessário, sem alterar a interface pública. Suponha que, em relação à funcionalidade, um método em uma classe execute a mesma operação com o mesmo resultado esperado toda vez que você o chamar com os mesmos parâmetros. Ele permite que o autor mude como a classe funciona, sua implementação, sem interromper a maneira como as pessoas interagem com ela.
E você pode programar para a interface, não para a implementação sem nunca usar uma construção de Interface. Você pode programar para a interface e não a implementação em C ++, que não possui uma construção de Interface. É possível integrar dois sistemas corporativos maciços com muito mais robustez, desde que eles interajam por meio de interfaces públicas (contratos), em vez de chamar métodos em objetos internos aos sistemas. Espera-se que as interfaces reajam sempre da mesma maneira esperada, considerando os mesmos parâmetros de entrada; se implementado na interface e não na implementação. O conceito funciona em muitos lugares.
Agite o pensamento de que as interfaces Java têm algo a ver com o conceito de 'Programa para a interface, não a implementação'. Eles podem ajudar a aplicar o conceito, mas eles são não o conceito.
fonte
Parece que você entende como as interfaces funcionam, mas não tem certeza de quando usá-las e quais vantagens elas oferecem. Aqui estão alguns exemplos de quando uma interface faria sentido:
então eu poderia criar GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider, etc.
em seguida, crie JpegImageLoader, GifImageLoader, PngImageLoader etc.
A maioria dos sistemas de suplementos e plugins funciona fora de interfaces.
Outro uso popular é para o padrão de repositório. Digamos que eu queira carregar uma lista de códigos postais de diferentes fontes
então eu poderia criar um XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository, etc. Para meus aplicativos Web, costumo criar repositórios XML no início, para que eu possa colocar algo em funcionamento antes que o banco de dados SQL esteja pronto. Quando o banco de dados estiver pronto, escrevo um SQLRepository para substituir a versão XML. O restante do meu código permanece inalterado, pois é executado apenas fora das interfaces.
Os métodos podem aceitar interfaces como:
fonte
Isso torna seu código muito mais extensível e fácil de manter quando você tem conjuntos de classes semelhantes. Como programador júnior, não sou especialista, mas acabei de terminar um projeto que exigia algo semelhante.
Trabalho no software do cliente que fala com um servidor executando um dispositivo médico. Estamos desenvolvendo uma nova versão deste dispositivo que possui alguns novos componentes que o cliente deve configurar às vezes. Existem dois tipos de novos componentes, e eles são diferentes, mas também são muito semelhantes. Basicamente, eu tive que criar dois formulários de configuração, duas classes de listas, duas de tudo.
Decidi que seria melhor criar uma classe base abstrata para cada tipo de controle que contenha quase toda a lógica real e, em seguida, os tipos derivados para cuidar das diferenças entre os dois componentes. No entanto, as classes base não seriam capazes de executar operações nesses componentes se eu tivesse que me preocupar com tipos o tempo todo (bem, eles poderiam ter, mas haveria uma instrução "if" ou alternaria em todos os métodos) .
Eu defini uma interface simples para esses componentes e todas as classes base conversam com essa interface. Agora, quando troco de algo, praticamente 'funciona' em todos os lugares e não tenho duplicação de código.
fonte
Muitas explicações por aí, mas para tornar ainda mais simples. Tomemos, por exemplo, a
List
. Pode-se implementar uma lista com:Ao criar uma interface, diga a
List
. Você codifica apenas quanto à definição da lista ou o queList
significa na realidade.Você pode usar qualquer tipo de implementação internamente, como uma
array
implementação. Mas suponha que você queira alterar a implementação por algum motivo, digamos, um bug ou desempenho. Então você só precisa alterar a declaraçãoList<String> ls = new ArrayList<String>()
paraList<String> ls = new LinkedList<String>()
.Em nenhum outro lugar no código, você terá que alterar qualquer outra coisa; Porque todo o resto foi construído sobre a definição de
List
.fonte
Se você programar em Java, o JDBC é um bom exemplo. O JDBC define um conjunto de interfaces, mas não diz nada sobre a implementação. Seus aplicativos podem ser escritos nesse conjunto de interfaces. Em teoria, você escolhe algum driver JDBC e seu aplicativo funcionaria. Se você descobrir que há um driver JDBC mais rápido, "melhor" ou mais barato ou por qualquer motivo, em teoria, você poderá reconfigurar seu arquivo de propriedades e, sem precisar fazer nenhuma alteração no aplicativo, o aplicativo continuará funcionando.
fonte
Programar para interfaces é incrível, pois promove um acoplamento solto. Como o @lassevk mencionou, a Inversão de Controle é um ótimo uso disso.
Além disso, consulte os princípios do SOLID . aqui está uma série de vídeos
Ele passa por um código rígido (exemplo fortemente acoplado) e depois analisa as interfaces, finalmente progredindo para uma ferramenta IoC / DI (NInject)
fonte
Estou atrasado nesta questão, mas quero mencionar aqui que a linha "Programa para uma interface, não uma implementação" teve uma boa discussão no livro de Padrões de Design do GoF (Gang of Four).
Afirmou, na p. 18:
e acima disso, começou com:
Portanto, em outras palavras, não escreva suas classes para que ele tenha um
quack()
método para patos e, em seguida, umbark()
método para cães, porque eles são muito específicos para uma implementação específica de uma classe (ou subclasse). Em vez disso, escreva o método usando nomes suficientemente genéricos para serem usados na classe base, comogiveSound()
ormove()
, para que possam ser usados para patos, cães ou até carros, e então o cliente de sua classe poderá apenas dizer, em.giveSound()
vez de pensando em usarquack()
oubark()
até mesmo determinar o tipo antes de emitir a mensagem correta a ser enviada ao objeto.fonte
Além da resposta já selecionada (e das várias postagens informativas aqui), eu recomendo pegar uma cópia do Head First Design Patterns . É uma leitura muito fácil e responderá sua pergunta diretamente, explicará por que é importante e mostrará muitos padrões de programação que você pode usar para fazer uso desse princípio (e outros).
fonte
Para adicionar às postagens existentes, às vezes a codificação para interfaces ajuda em grandes projetos quando os desenvolvedores trabalham em componentes separados simultaneamente. Tudo o que você precisa é definir interfaces com antecedência e gravar código nelas, enquanto outros desenvolvedores gravam código na interface que você está implementando.
fonte
Também é bom para o teste de unidade, você pode injetar suas próprias classes (que atendem aos requisitos da interface) em uma classe que depende dela
fonte
Pode ser vantajoso programar para interfaces, mesmo quando não dependemos de abstrações.
A programação para interfaces nos obriga a usar um subconjunto contextualmente apropriado de um objeto . Isso ajuda porque:
Por exemplo, considere uma
Person
classe que implementaFriend
aEmployee
interface e.No contexto do aniversário da pessoa, programamos para a
Friend
interface, para evitar tratar a pessoa como umEmployee
.No contexto do trabalho da pessoa, programamos para a
Employee
interface, para evitar que os limites do local de trabalho sejam confusos.Ótimo. Nos comportamos adequadamente em diferentes contextos e nosso software está funcionando bem.
No futuro, se nossa empresa mudar para trabalhar com cães, podemos mudar o software com bastante facilidade. Primeiro, criamos uma
Dog
classe que implementa ambosFriend
eEmployee
. Então, nós mudamos com segurançanew Person()
com paranew Dog()
. Mesmo se as duas funções tiverem milhares de linhas de código, essa edição simples funcionará porque sabemos o seguinte:party
usa apenas oFriend
subconjunto dePerson
.workplace
usa apenas oEmployee
subconjunto dePerson
.Dog
implementa tanto oFriend
eEmployee
interfaces.Por outro lado, se um
party
ouworkplace
deveria ter sido programadoPerson
, haveria o risco de ambos terem umPerson
código específico. Mudar dePerson
paraDog
exigiria que vasculhassemos o código para extirpar qualquerPerson
código específico queDog
não suporte.A moral : programar para interfaces ajuda nosso código a se comportar adequadamente e a estar pronto para a mudança. Também prepara nosso código para depender de abstrações, o que traz ainda mais vantagens.
fonte
Se eu estiver escrevendo uma nova classe
Swimmer
para adicionar a funcionalidadeswim()
e precisar usar um objeto da classe digamosDog
, e essaDog
classe implementa a interfaceAnimal
que declaraswim()
.No topo da hierarquia (
Animal
), é muito abstrato, enquanto na parte inferior (Dog
) é muito concreto. A maneira como penso em "programar para interfaces" é que, enquanto escrevoSwimmer
classe, quero escrever meu código na interface que está na hierarquia que, neste caso, é umAnimal
objeto. Uma interface está livre de detalhes de implementação e, portanto, torna seu código fracamente acoplado.Os detalhes da implementação podem ser alterados com o tempo, no entanto, isso não afetaria o código restante, pois tudo com o qual você está interagindo é com a interface e não com a implementação. Você não se importa como é a implementação ... tudo o que você sabe é que haverá uma classe que implementaria a interface.
fonte
Portanto, apenas para acertar, a vantagem de uma interface é que eu posso separar a chamada de um método de qualquer classe específica. Em vez de criar uma instância da interface, em que a implementação é fornecida de qualquer classe que eu escolher que implementa essa interface. Assim, permitindo-me ter muitas classes, que têm funcionalidades semelhantes, mas ligeiramente diferentes, e em alguns casos (os casos relacionados à intenção da interface) não se importam com qual objeto.
Por exemplo, eu poderia ter uma interface de movimento. Um método que faz algo 'se mover' e qualquer objeto (Pessoa, Carro, Gato) que implementa a interface de movimento pode ser passado e instruído a se mover. Sem o método, todos sabem o tipo de classe que é.
fonte
Imagine que você tenha um produto chamado 'Zebra' que pode ser estendido por plugins. Ele encontra os plugins pesquisando DLLs em algum diretório. Ele carrega todas essas DLLs e usa reflexão para encontrar todas as classes que implementam
IZebraPlugin
e, em seguida, chama os métodos dessa interface para se comunicar com os plug-ins.Isso o torna completamente independente de qualquer classe de plug-in específica - não se importa com o que são as classes. Só importa que eles atendam às especificações da interface.
As interfaces são uma maneira de definir pontos de extensibilidade como este. O código que fala com uma interface é mais fracamente acoplado - na verdade, não está acoplado a nenhum outro código específico. Ele pode interagir com plug-ins escritos anos depois por pessoas que nunca conheceram o desenvolvedor original.
Você poderia usar uma classe base com funções virtuais - todos os plugins seriam derivados da classe base. Mas isso é muito mais limitador porque uma classe pode ter apenas uma classe base, enquanto pode implementar qualquer número de interfaces.
fonte
Explicação C ++.
Pense em uma interface como seus métodos públicos de classes.
Você pode criar um modelo que 'depende' desses métodos públicos para executar sua própria função (faz chamadas de função definidas na interface pública das classes). Digamos que esse modelo seja um contêiner, como uma classe Vector, e a interface da qual ele depende é um algoritmo de pesquisa.
Qualquer classe de algoritmo que defina as funções / interfaces para as quais o vetor faz chamadas satisfará o 'contrato' (como alguém explicou na resposta original). Os algoritmos nem precisam ser da mesma classe base; o único requisito é que as funções / métodos dos quais o vetor depende (interface) sejam definidas no seu algoritmo.
O objetivo de tudo isso é que você poderia fornecer qualquer algoritmo / classe de pesquisa diferente, desde que ele fornecesse a interface da qual o Vector depende (pesquisa de bolhas, pesquisa seqüencial, pesquisa rápida).
Você também pode projetar outros contêineres (listas, filas) que usariam o mesmo algoritmo de pesquisa que Vector, fazendo com que eles cumprissem a interface / contrato do qual seus algoritmos de pesquisa dependem.
Isso economiza tempo (princípio de OOP 'reutilização de código'), pois você é capaz de escrever um algoritmo uma vez, em vez de uma e outra vez e de uma vez por outra específico para cada novo objeto que você cria, sem complicar demais o problema com uma árvore de herança crescida.
Quanto a 'perder' como as coisas funcionam; grande momento (pelo menos em C ++), pois é assim que a maioria da estrutura da Standard TEMPLATE Library opera.
Obviamente, ao usar classes de herança e abstratas, a metodologia de programação para uma interface muda; mas o princípio é o mesmo, suas funções / métodos públicos são sua interface de classes.
Este é um tópico enorme e um dos princípios fundamentais dos Design Patterns.
fonte
Em Java, essas classes concretas implementam a interface CharSequence:
Essas classes concretas não têm uma classe pai comum que não seja Object, portanto, não há nada que as relacione, exceto o fato de que cada uma delas tem algo a ver com matrizes de caracteres, representando ou manipulando tais. Por exemplo, os caracteres de String não podem ser alterados depois que um objeto String é instanciado, enquanto os caracteres de StringBuffer ou StringBuilder podem ser editados.
No entanto, cada uma dessas classes é capaz de implementar adequadamente os métodos da interface CharSequence:
Em alguns casos, as classes da biblioteca de classes Java que costumavam aceitar String foram revisadas para agora aceitar a interface CharSequence. Portanto, se você tiver uma instância do StringBuilder, em vez de extrair um objeto String (o que significa instanciar uma nova instância do objeto), poderá passar o próprio StringBuilder ao implementar a interface CharSequence.
A interface Appendable implementada por algumas classes tem o mesmo tipo de benefício para qualquer situação em que os caracteres possam ser anexados a uma instância da instância de objeto de classe concreta subjacente. Todas essas classes concretas implementam a interface Appendable:
fonte
CharSequence
são tão anêmicas. Eu gostaria que Java e .NET permitissem que interfaces tivessem implementação padrão, para que as pessoas não analisassem as interfaces apenas com o objetivo de minimizar o código padrão. Dada qualquerCharSequence
implementação legítima, pode-se emular a maioria das funçõesString
usando apenas os quatro métodos acima, mas muitas implementações podem executar essas funções com muito mais eficiência de outras maneiras. Infelizmente, mesmo que uma implementação específica deCharSequence
tenha tudo em um únicochar[]
e possa executar muitos ... #indexOf
rapidamente, não há como um chamador que não esteja familiarizado com uma implementação específicaCharSequence
possa solicitar isso, em vez de precisar usarcharAt
para examinar cada caractere individual.Breve história: Um carteiro é solicitado a ir para casa depois de casa e receber as capas (cartas, documentos, cheques, cartões-presente, inscrição, carta de amor) com o endereço escrito para entregar.
Suponha que não haja cobertura e peça ao carteiro que volte para casa depois de casa e receba todas as coisas e entregue a outras pessoas, pois o carteiro pode ficar confuso.
Então é melhor envolvê-lo com capa (em nossa história, é a interface), para que ele faça seu trabalho bem.
Agora, o trabalho do carteiro é receber e entregar apenas as capas (ele não se incomodou com o que está dentro da capa).
Crie um tipo de tipo
interface
não real, mas implemente-o com o tipo real.Criar interface significa que seus componentes se encaixam facilmente no restante do código
Eu te dou um exemplo.
você tem a interface AirPlane como abaixo.
Suponha que você tenha métodos em sua classe de planos Controller, como
e
implementado em seu programa. Não quebrará seu código. Quero dizer, ele não precisa mudar desde que aceite argumentos como
AirPlane
.Porque ele vai aceitar qualquer avião apesar tipo real,
flyer
,highflyr
,fighter
, etc.Além disso, em uma coleção:
List<Airplane> plane;
// Vai pegar todos os seus aviões.O exemplo a seguir irá esclarecer sua compreensão.
Você tem um avião de combate que o implementa, então
A mesma coisa para o HighFlyer e outras classes:
Agora pense em suas classes de controlador usando
AirPlane
várias vezes,Suponha que sua classe Controller seja ControlPlane, como abaixo,
Aí vem a mágica, pois você pode fazer com que suas novas
AirPlane
instâncias de tipo sejam quantas quiser e não está alterando o código deControlPlane
classe.Você pode adicionar uma instância ...
Você também pode remover instâncias de tipos criados anteriormente.
fonte
Uma interface é como um contrato, em que você deseja que sua classe de implementação implemente métodos escritos no contrato (interface). Como o Java não fornece herança múltipla, "programar para interface" é uma boa maneira de obter herança múltipla.
Se você possui uma classe A que já está estendendo outra classe B, mas deseja que ela também siga certas diretrizes ou implemente um determinado contrato, poderá fazê-lo pela estratégia "programação para interface".
fonte
Nota: Não foi possível instanciar uma interface não implementada por uma classe - True.
Nota: Agora poderíamos entender o que aconteceu se Bclass e Cclass implementassem o mesmo Dintf.
O que temos: Os mesmos protótipos de interface (nomes de funções na interface) e chamam implementações diferentes.
Bibliografia: Protótipos - wikipedia
fonte
O programa para uma interface permite alterar a implementação do contrato definido pela interface sem problemas. Permite um acoplamento flexível entre o contrato e as implementações específicas.
Dê uma olhada nesta pergunta SE para um bom exemplo.
Por que a interface para uma classe Java deve ser preferida?
Sim. Ele terá uma leve sobrecarga de desempenho em sub-segundos. Mas se o seu aplicativo precisar alterar dinamicamente a implementação da interface, não se preocupe com o impacto no desempenho.
Não tente evitar várias implementações de interface se seu aplicativo precisar delas. Na ausência de acoplamento rígido da interface com uma implementação específica, talvez seja necessário implantar o patch para alterar uma implementação para outra implementação.
Um bom caso de uso: Implementação do padrão de estratégia:
Exemplo do mundo real do padrão de estratégia
fonte
programa para uma interface é um termo do livro do GOF. Eu não diria diretamente que tem a ver com a interface java, mas com interfaces reais. Para obter uma separação de camada limpa, é necessário criar uma separação entre os sistemas, por exemplo: digamos que você tenha um banco de dados concreto que deseja usar, nunca "programaria no banco de dados", mas sim "programaria na interface de armazenamento". Da mesma forma, você nunca "programa para um serviço da Web", mas sim para uma "interface do cliente". isso é para que você possa trocar facilmente as coisas.
Acho que essas regras me ajudam:
1 . usamos uma interface java quando temos vários tipos de um objeto. se eu tiver apenas um objeto, não entendo o ponto. se houver pelo menos duas implementações concretas de alguma idéia, eu usaria uma interface java.
2 . se, como afirmei acima, você deseja trazer a dissociação de um sistema externo (sistema de armazenamento) para o seu próprio sistema (banco de dados local), use também uma interface.
observe como existem duas maneiras de considerar quando usá-las. espero que isto ajude.
fonte
Também vejo muitas respostas boas e explicativas aqui, por isso quero dar meu ponto de vista aqui, incluindo algumas informações extras que eu notei ao usar esse método.
Teste de unidade
Nos últimos dois anos, escrevi um projeto de hobby e não escrevi testes de unidade para ele. Depois de escrever cerca de 50 mil linhas, descobri que seria realmente necessário escrever testes de unidade. Não usei interfaces (ou muito pouco) ... e quando fiz meu primeiro teste de unidade, descobri que era complicado. Por quê?
Porque eu tive que criar muitas instâncias de classe, usadas para entrada como variáveis e / ou parâmetros de classe. Portanto, os testes se parecem mais com testes de integração (tendo que criar uma 'estrutura' completa de classes, pois tudo estava vinculado).
Medo de interfaces Então eu decidi usar interfaces. Meu medo era que eu tivesse que implementar todas as funcionalidades em todos os lugares (em todas as classes usadas) várias vezes. De alguma forma, isso é verdade, porém, usando a herança, pode-se reduzir muito.
Combinação de interfaces e herança Descobri que a combinação é muito boa de ser usada. Eu dou um exemplo muito simples.
Dessa forma, a cópia do código não é necessária, enquanto ainda há o benefício de usar um carro como interface (ICar).
fonte
Vamos começar com algumas definições primeiro:
Interface n. O conjunto de todas as assinaturas definidas pelas operações de um objeto é chamado de interface para o objeto
Digite n. Uma interface específica
Um exemplo simples de uma interface de , tal como definido acima seria todos os métodos DOP de objectos, tais como
query()
,commit()
,close()
etc., como um todo, não separadamente. Esses métodos, ou seja, sua interface definem o conjunto completo de mensagens, solicitações que podem ser enviadas ao objeto.Um tipo como definido acima é uma interface específica. I vai utilizar a interface de forma feita para demonstrar-se:
draw()
,getArea()
,getPerimeter()
etc ..Se um objeto é do tipo Banco de dados, significa que ele aceita mensagens / solicitações da interface do banco de dados
query()
,commit()
etc. Os objetos podem ser de vários tipos. Você pode fazer com que um objeto de banco de dados seja do tipo de forma, desde que implemente sua interface; nesse caso, isso seria uma sub-digitação .Muitos objetos podem ter muitas interfaces / tipos diferentes e implementar essa interface de maneira diferente. Isso nos permite substituir objetos, deixando-nos escolher qual deles usar. Também conhecido como polimorfismo.
O cliente só estará ciente da interface e não da implementação.
Portanto, em essência, programar para uma interface envolveria criar algum tipo de classe abstrata, como
Shape
a interface especificada apenasdraw()
, ou sejagetCoordinates()
,getArea()
etc. E então, diferentes classes concretas implementam essas interfaces, como uma classe Circle, Square, Triangle. Daí o programa para uma interface, não uma implementação.fonte
"Programa para interface" significa não fornecer código rígido da maneira certa, o que significa que seu código deve ser estendido sem interromper a funcionalidade anterior. Apenas extensões, não editando o código anterior.
fonte