Interface x Clase abstrata

45 respostas
P

Olá. Antes que me ataquem por ser um tópico muitíssimo duplicado, quero explicar minha dúvida.
Conheço bem a diferença técnica entre uma Interface e uma classe abstrata, porém nesse momento parei para pensar e vi que eu não sei explicar o porque de usar uma Interface ao invés de uma classe abstrata. As duas possuem recursos diferentes, porém eu posso muito bem fazer o trabalho de uma Interface em uma classe abstrata. Daí vai a minha dúvida, porque foi criada a Interface? Já vi gente que diz que foi para resolver o problema de múltipla herança, mas creio que ainda há uma resposta mais sensata.
Valeu :smiley:

45 Respostas

jeffev

Talvez o link abaixo possa lhe ajudar.

drsmachado

Então você não conhece bem a diferença entre uma e outra.
Pense no seguinte caso:
Eu tenho duas implementações da interface A, AB e AC.
A possui 10 métodos mapeados, que serão implementados por AB e AC, que não tem relação de herança entre eles, tampouco de agregação ou composição.
Acontece que alguns métodos implementados por AB e AC terão a mesma funcionalidade.
Por estarmos usando uma interface, somos obrigados a implementar a mesma lógica dentro dos métodos idênticos em AB e AC.

Agora, se usássemos uma classe abstrata B para implementar A e estendessemos AB e AC de B, teríamos a possibilidade de implementar em B os métodos iguais e em AB e AC os métodos específicos.

Sacou?

RafaelCassau

Bom dia amigo, realmente existem diferenças entre classes abstratas e interfaces, entre elas classe abstrata pode ter metodos implementados, interface não, uma interface pode ser instanciada apesar de nunca ser, uma classe abastrata só pode ser herdada, o problema é que o conceito de herança fere o encapsulamento fazendo com que as classes especializadas conhecam muito bem as super classes ou classes mais genericas, agora vamos a um exemplo simples, você tem uma classe funcionario que tem um metodo de autenticação em um sistema interno da empresa, ae você tem um gerente que herda de funcionario, até porque um gerente também é um funcionario, porem ambos tem previlegios diferentes, simples é só sobreescrever o método autentica, até ae a herança serviu muito bem, porem digamos que esse sistema é um site de consultas e você tem clientes que também se autenticam no sistema, e você concorda que um cliente não é um funcionário e se herdassemos as caracteristicas do mesmo iriamos conhecer de mais seus atributos e ferir o encapsulamento, enão podemos usar a interface que tenha um método autentica e que tanto funcionario, gerente e cliente implementa esse método de maneira diferente, ou seja, uma interface faz com que seja possivel o uso de polimorfismo mesmo em classes que não tem nenhum vinculo de herança, porem ambas irão implementar o mesmo comportamento de formas diferentes, espero ter ajudado.

t+

Rodrigo_Sasaki

Em um post eu falei um pouco sobre isso. É exatamente a ideia conceitual que o drsmachado apresentou, porém se quiser um exemplo mais prático, talvez para dar uma clarificada melhor, dê uma lida :slight_smile: Sei que o exemplo não trata de classes abstratas, mas a ideia é a mesma.

FernandoFranzini

No Java effective tem tudo sobre isso e muitos outras duvidas…- http://fernandofranzini.wordpress.com/2012/08/07/java-efetivo-aprenda-realmente-a-programar-java/

G

RafaelCassau:
Bom dia amigo, realmente existem diferenças entre classes abstratas e interfaces, entre elas classe abstrata pode ter metodos implementados, interface não, uma interface pode ser instanciada apesar de nunca ser, uma classe abastrata só pode ser herdada, o problema é que o conceito de herança fere o encapsulamento fazendo com que as classes especializadas conhecam muito bem as super classes ou classes mais genericas, agora vamos a um exemplo simples, você tem uma classe funcionario que tem um metodo de autenticação em um sistema interno da empresa, ae você tem um gerente que herda de funcionario, até porque um gerente também é um funcionario, porem ambos tem previlegios diferentes, simples é só sobreescrever o método autentica, até ae a herança serviu muito bem, porem digamos que esse sistema é um site de consultas e você tem clientes que também se autenticam no sistema, e você concorda que um cliente não é um funcionário e se herdassemos as caracteristicas do mesmo iriamos conhecer de mais seus atributos e ferir o encapsulamento, enão podemos usar a interface que tenha um método autentica e que tanto funcionario, gerente e cliente implementa esse método de maneira diferente, ou seja, uma interface faz com que seja possivel o uso de polimorfismo mesmo em classes que não tem nenhum vinculo de herança, porem ambas irão implementar o mesmo comportamento de formas diferentes, espero ter ajudado.

t+

só discordei do “uma interface pode ser instanciada”.

a classe anonima não pode passar desapercebida.

qdo eu tava nessa caminhada de entender o uso de intefaces, eu sempre procurava um exemplo q demonstrasse com clareza, q se resolveria com interface e não se resolveria com class abstrata.

no seu exemplo mesmo poderia ter uma classe:

Autenticavel

e q tanto Funcionario qto Clientes herdavam dela.

então eu continuava achando q não houve necessidade da interface.

até q um dia descobri q Funcionario e Cliente ja herdavam de Pessoa.
e Pessoa não poderia herdar de Autenticavel pq nem td Pessoa era Autenticavel

lina

Oi,

Uma interface deve ser criada se existir ao menos um fator comum entre duas ou mais classes.

Tchauzin!

E

Você gosta de exemplos relacionados a carros?
Pense na interface como sendo uma especificação, do tipo “automóvel de passageiros” e na classe abstrata como “plataforma Polo”.
Como você deve saber, vocâ não pode comprar uma “plataforma Polo” em uma concessionária da Volkswagen (a “plataforma Polo” seria uma classe abstrata, já que ela implementa várias características comuns mas não implementa todas), mas pode comprar um Gol, um Polo ou um Fox (que são construídos sobre a “plataforma Polo”). Gol, Polo e Fox seriam classes concretas, e um automóvel Gol, Polo ou Fox seria uma instância (um objeto) de cada uma dessas classes concretas.
Quando você vai comprar um carro, você quer apenas um “automóvel de passageiros” (algo que tenha determinadas funcionalidades, que podem ser implementadas de diferentes maneiras por diferentes fabricantes), portanto você está interessado apenas na interface.

RafaelCassau

Boa tarde GilsonNunes, realmente a interface não é instanciada, eu errei na minha colocação, quiz dizer que é possivel refazer uma implementação default de uma interface por exemplo List, Map, etc, referente ao exemplo da autenticavel, como o JAVA não permite herança multipla seria impossivel por exemplo um gerente ser funcionario e também autenticavel, por isso falamos que o gerente é um funcionário e o mesmo implementa o comportamento autenticavel certo? E só para constar mesmo que você faça com que um gerente herde de autenticavel isso feririria o encapsulamento pois o gerente precisaria conhecer muito sobre autenticavel, o intuito do meu exemplo foi justificar que com uma interface um contrato é estabelecido, já com uma classe abstrata comportamentos são herdados dentre eles varios comportamentos indevidos que deverão ser reemplementados.

sergiotaborda

pedroe:
Olá. Antes que me ataquem por ser um tópico muitíssimo duplicado, quero explicar minha dúvida.
Conheço bem a diferença técnica entre uma Interface e uma classe abstrata, porém nesse momento parei para pensar e vi que eu não sei explicar o porque de usar uma Interface ao invés de uma classe abstrata. As duas possuem recursos diferentes, porém eu posso muito bem fazer o trabalho de uma Interface em uma classe abstrata. Daí vai a minha dúvida, porque foi criada a Interface? Já vi gente que diz que foi para resolver o problema de múltipla herança, mas creio que ainda há uma resposta mais sensata.

A diferença entre interface e class abstrata não é de implementação. Não é sobre se uma permite herança multipla ou se uma não precisa de implementação. Essa não é a diferença.

A diferença de prende com duas dimensões : identidade e comportamento.

Uma classe abstrata fixa uma identidade. Calendar é uma classe abstrata. O que é Calendar não pode ser nenhuma outra coisa. Isto não é porque o java não permite herança multipla. Isto e´assim conceptualmente, em OO independenmente da tecnologia.
Só que além de um identidade uma classe abstrata pode também fixar um comportamento (que é o caso de Calendar). Todas as filhas da classe abstrata X não apenas são X como se comportam da mesma forma que X e essa forma é ditada por X. Este fixar é opcional,porque eu posso querer apenas fixar a identidade.

Um interface não fixa a identidade mas fixa o comportamento ( o contrato) contudo não fixa como o comportamento é atingido.
Ou seja, se Y é uma interface, todas as implementações de Y podem ser coisas diferentes de Y, mas comportam-se como Y , mas de uma forma que não é ditada por Y.
List é um interface que estabelece um contrato (um comportamento) mas dita como esse comportamento tem que ser implementado. Por isso ha tantas implementações de List.

A diferença maior é poder fixar a identidade. Uma classe fixa uma identidade, uma taxionomia. Uma interface não.
O comportamento sempre é ditado pela interface da mesma forma que a classe abstrata porqu ambas definem contratos.
A interface não pode ditar comportamentos padrão , a class abstrata sim. Estes comportamentos são inerentes ao tipo.

Este ultimo conceito de ditar o comportamento irá alterar-se no java 8 com os métodos default, em que as interfaces podem ditar implementações para os seus métodos, mas mesmo aqui a interface não está ditando (pois ela não consegue proibir o override usando final) está apenas sugerindo como contigência.

O resto é como estes conceitos são traduzidos em java.

Tecnicamente deveriamos falar em contratos em vez de interface pois interface é apenas um construto do java e não necessáriamente um padrão OO. É um tipo possivel. O trait, usado em Scala e outras linguagens, consegue expressar o mesmo que a interface java em termos de contrato mais vai mais longe deixando estabalecer métodos default ( o java 8 com as suas interfaces com métodos default está na realidade dando opção de implementar traits) .

B

Eu recomendo dar uma olhada no código-fonte e no JavaDoc do Java Collections Framework, no uso que eles fazem de interfaces e abstract classes. Em específico olhe a Iterable, Collection, AbstractCollection, List, AbstractList, ArrayList, AbstractSequentialList, LinkedList, Set, AbstractSet e TreeSet. Tendo tempo, veja também o Iterator e suas classes implementadoras.

Eles fazem o melhor e mais claro uso de interfaces e abstract classes que conheço.

P

Hehehe eu suspeitei que os comentários seriam deste tipo… eu conheço bem o que pode e não pode em cada uma, o que eu quero dizer é o seguinte:
Se não existisse Interface eu poderia muito bem utilizar uma classe abstrata para fazer tudo o que ela faz. Ou estou enganado?
As respostas aqui foram todas técnicas, porém o que eu queria desde o começo é uma resposta prática.
Se eu perguntar pra você o porque de eu usar uma Interface e não uma classe abstrata, tem resposta?
Esqueçam o lado “melhor prática” ou “classe abstrata pode implementar métodos, Interfaces não…”

E obrigado pelas respostas ainda assim :smiley:

wagnerfrancisco

Em algumas situações você realmente poderia usar classes abstratas ao invés de interfaces. Mesmo tecnicamente possível, é errado, por tudo que já foi citado.

Mas há situações que realmente não é possível. Por exemplo, você não pode criar mixins usando uma classe abstrata - implementar um tipo além do tipo primário da classe. Um exemplo simples?

Você tem a classe Funcionario e a classe Gerente, que herda de Funcionario. Aí você precisa implementar a interface Comparable para o Gerente. Sendo uma interface, tá tranquilo. Mas e se não houvesse interface? Se Comparable fosse uma classe abstrata? Gerente não ia poder herdar de Comparable, por que já herda de Funcionario. Pronto, tá aí uma limitação prática. :smiley:

G

sim vc falou certo. o q eu quiz dizer é q poderia argumentar q, ainda assim, seria possivel resolver com classe abstrata.

bastava Funcionario e Cliente herdarem de Autenticavel.

Rodrigo_Sasaki

GilsonNunes:
sim vc falou certo. o q eu quiz dizer é q poderia argumentar q, ainda assim, seria possivel resolver com classe abstrata.

bastava Funcionario e Cliente herdarem de Autenticavel.


Como se Funcionario e Cliente já herdam de Pessoa ?

RafaelCassau

digaoneves:
GilsonNunes:
sim vc falou certo. o q eu quiz dizer é q poderia argumentar q, ainda assim, seria possivel resolver com classe abstrata.

bastava Funcionario e Cliente herdarem de Autenticavel.


Como se Funcionario e Cliente já herdam de Pessoa ?

eu quiz dizer exatamente o que o digaoneves disse, isso não seria possivel por causa da herança multipla e também o que eu quiz dizer em tudo isso que talvez alguns companheiros não entenderam falando que eu disse que a diferença era herança multipla ou qualquer outra que seja, o que eu quiz dizer é que a interface é bem mais flexiviel fazendo com que entidades diferentes possam implementar comportamento em comum que ambas possuem de formas diferentes fazendo com que o uso de polimorfismo se torne possivel, fazendo também que o software a ser desenvolvido tenha menos acoplamento e alta coesão.

espero ter ajudado

G

digaoneves:
GilsonNunes:
sim vc falou certo. o q eu quiz dizer é q poderia argumentar q, ainda assim, seria possivel resolver com classe abstrata.

bastava Funcionario e Cliente herdarem de Autenticavel.


Como se Funcionario e Cliente já herdam de Pessoa ?

então era só Pessoa herdar de Autenticavel.

eu entendi o q vcs estão dizendo. só estou frisando q no intuito de entender, eu fazia essas indagações.
q é o mesmo q o autor do tópico está fazendo.

e ele está certo em querer entender a razão q as justificam. mas no meu post eu tentei citar um exemplo prático pra auxiliar no entendimento.

e sei q as coisa não é tão simples assim. vejamos o exemplo do Comparable q tem o CompareTo.

se a classe Object tivesse o CompareTo, tb não resolveria?
ta certo q alguem vai dizer: mas não tem.
mas aí corre o risco de ficar a impressão q a interface veio somente para “corrigir”.

C

A interface é um contrato, sendo este portanto ela define una e exclusivamente o básico para que alguém interaja com ela.
A classe abstrata é um abstração de comportamentos padrões.
Na pratica, caso a herança múltipla existisse, uma classe abstrata poderia substituir a interface, porém é errado, a nível de design. Considerando no raciocínio do que é possível ser feito, podemos eliminar as classes abstratas também. tanto quanto podemos fazer muitas outra gambiarras que fujam as boas práticas porém funcionem, e na pratica o resultado inicial é o mesmo, porém os problemas a longo prazo são óbvios, quando o estagiário for meter a mão ele vai implementar um método que não pertence a todos, mas a uma parte deles, na classe abstrata, e vai foder com o seu encapsulamento, e assim vai pro buraco a manutibilidade do seu código.
Portanto, na pratica, a uma primeira vista, a interface a a classe abstratas são semelhantes, porém cada uma tem sua aplicabilidade bem definida no projeto do sistema, e que se bem usadas permitem ao sistema existir por mais tempo sem cair na classificação de legado.

G

mas o fato de usar interfaces, não elimina o uso da classe abstrata, logo esse risco continua existindo.
e ainda, a classe abstrata leva uma vantagem (**ao menos no java): vc poderia implementar algo q fosse util a tds.

**pq em algumas outras linguagens é possivel uma interface implementar metodos. funciona como Helper.

um exemplo prático é a interface OutputStream.

ela tem um metodo Write q escreve um byte.
mas ela não tem um writeBytes, nem um writeInt, etc.
e não seria viável ter, pq forçaria td mundo ter q implementá-los e seria tds idênticos.
mas fosse uma classe abstrata ela poderia implementar visto q ela não precisaria saber como escrever, bastava ela chamar o write q era abstrato.

ou seja, eliminaria a necessidade de um DataOutput e de um DataOutputStream, q a sua unica razão de ser, é a ausência de algo no OutputStream.

G

pessoal foi mal.
o OutputStream não é interface não.

me desculpem a confusão ai.

ViniGodoy
pedroe:
Se não existisse Interface eu poderia muito bem utilizar uma classe abstrata para fazer tudo o que ela faz. Ou estou enganado?

Você não pode reescrever qualquer código com interfaces usando classes abstratas.

Por pensar assim, você está considerando que:
a) Você sempre pode reescrever a interface na forma de uma classe abstrata;
b) Você tem total controle sobre todas as partes do código.

Esse pensamento não é válido se você estiver lidando com uma biblioteca de terceiros, ou criando uma biblioteca para terceiros utilizarem.

Tente resolver esse problema com classes abstratas. Considere que as ProcessoPesado e Desenhavel são interfaces duas bibliotecas diferentes, que não foi implementada por você, nem pela mesma pessoa.

public interface ProcessoPesado {
    void processar();
}

public interface Desenhavel {
   void desenhar(Graphics2D g);
}

public class Exemplo implements ProcessoPesado 
{
     public void processar() {
        //Faz qualquer processamento pesado aqui
     }   
}

public class Exemplo2 extends Exemplo implements Desenhavel {
    public void desenhar(Graphics2D g) {
       //Faz um lindo desenho aqui
    }
}

Como você reescreveria esse código, caso as bibliotecas tivessem fornecido classes abstratas?

Lembre-se que as bibliotecas provavelmente terão métodos como:
void executarProcessoNoAzureServer(ProcessoPesado p);
void desenharUsandoDirectX(Desenhavel d);

E que, como você baixou essas bibliotecas na forma de um .jar compilado, você não pode alterar o parâmetro de entrada desses métodos.

As interfaces são legais pelo que o Sergio falou. Aqui, a lib externa está apenas preocupada no comportamento do que quer que seja passado para ela.
Não interessa o que seja um processo pesado, desde que ele tenha o comportamento de "processar()".
Não interessa também o que seja um Desenhavel, desde que ele tenha o comportamento de "desenhar()".

Desde que a classe de quem usa a lib, não importando onde esteja na hierarquia, diga que está de acordo com esse comportamento (ou seja, ela está de acordo com o "contrato"), então, ela poderá ser usada pela lib.

Note que isso vale se você também estiver escrevendo uma biblioteca para outros usarem. Ao declarar suas interfaces, você diz quais métodos espera que uma classe tenham, e fornece um serviço para quem implementa-los, sem se preocupar com que classe exatamente faz isso.

J

Olá

em relação a pergunta concreta do pedroe

acho que a resposta está aqui:

http://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html

Chapter 9. Interfaces
[…]
Programs can use interfaces to make it unnecessary for related classes to share a common abstract superclass or to add methods to Object.
[…]
Que numa tradução livre se pode entender como:
“Os programas podem usar interfaces para tornar desnecessária, para as classes relacionadas, compartilhar uma superclasse abstrata comum ou para adicionar métodos para a Object.”

Lendo isso ao contrário, acho que fica claro que a resposta é sim. O contexto é que determina o que deverá ser usado.

Abs.

wagnerfrancisco

joagostini:
Olá

em relação a pergunta concreta do pedroe

acho que a resposta está aqui:

http://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html

Chapter 9. Interfaces
[…]
Programs can use interfaces to make it unnecessary for related classes to share a common abstract superclass or to add methods to Object.
[…]
Que numa tradução livre se pode entender como:
“Os programas podem usar interfaces para tornar desnecessária, para as classes relacionadas, compartilhar uma superclasse abstrata comum ou para adicionar métodos para a Object.”

Lendo isso ao contrário, acho que fica claro que a resposta é sim. O contexto é que determina o que deverá ser usado.

Abs.

Releia o tópico que você verá que foram apresentados argumentos sobre situações onde não é possível empregar uma classe abstrata.

J

Olá wagnerfrancisco

Não discordo disso. Acho que se não existisse a interface, algo teria que ser feito para implementá-la.
Apenas me restringi à intenção da pergunta: saber se é possível fazer com uma classe abstrata o que se faz com uma interface. Sim, é possível.
Agora, posso fazer tudo com uma classe abstrata, prescindindo de uma interface? Não, não é possível. As várias respostas do tópico mostraram isso.
As duas classes são diferentes, com propósitos diferentes. Portanto, usos diferentes.
Entretanto, há várias possibilidades de se usar uma classe abstrata que dispensariam o uso da interface, mas não a eliminam e nem a substituem.
Depende do caso concreto.

ViniGodoy

Sim. Aí entra no mérito de “ser possível” e “ser inteligente”.

Muita coisa é “teoricamente possível”, mas é inadequada e trará problemas no futuro.

Depender seu código de implementações no lugar de interfaces é uma delas.

Até porque, isso gera transtornos incríveis, caso você esteja programando uma lib para alguém.

P

Desculpem se ainda não me convenci das respostas, mas vou argumentar novamente.

Quando digo classe abstrata estou me referindo mais especificamente a métodos abstratos.

Por exemplo:

public interface Foo {
    void jump();
}

public abstract class Foo {
    abstract void jump();
}

Qual a diferença entre as duas implementações?
Em ambas eu defino um contrato a ser seguido. Se eu criar uma classe que só possua métodos abstratos, não irei estar criando uma espécie de interface?

P

Este é um exemplo de quem defende a Interface por ser “herança multipla”. Nesse exemplo eu concordo, mas se observar no meu primeiro post do tópico, eu quero justamente encontrar uma explicação diferente desta, pois acho que existe um motivo para a existencia de Interfaces além deste.

ViniGodoy

pedroe:
Desculpem se ainda não me convenci das respostas, mas vou argumentar novamente.

Quando digo classe abstrata estou me referindo mais especificamente a métodos abstratos.

Por exemplo:

public interface Foo {
    void jump();
}

public abstract class Foo {
    abstract void jump();
}

Qual a diferença entre as duas implementações?

As diferenças são as seguintes:

a) Na segunda, quem herdar essa classe cria uma relação de tipos (como explicado pelo Sérgio). Essa relação é muito mais forte do que simplesmente o cumprimento de um contrato.

b) Na primeira,  a garantia de que nenhum programador irá incluir ali um atributo ou método implementado;

c) A segunda pode ser implementada em qualquer nível da hierarquia de classes de seu usuário;

Sim. Toda classe abstrata também define uma espécie de contrato. Entretanto, a relação é muito mais forte, pois você está criando um compromisso com a implementação, e não só com o comportamento. Esse compromisso existe mesmo que, a princípio, sua classe esteja vazia - como a que você colocou. Afinal, nada impede que com o passar do tempo, no decorrer do projeto, alguém modifique ali e inclua atributos e métodos com código.

Dizer que você é um subtipo de outro é uma das relações mais fortes que existem em OO. Ela geralmente implica em ter que revisar o comportamento da classe filha, caso o da classe pai mude.
Entretanto, dizer que você só implementa um contrato de comportamento é uma relação fraca.

Em algumas linguagens, como o C++, criar uma classe abstrata sem implementações é uma das únicas formas de se declarar interfaces. Entretanto, nesse caso, você está contando com a boa vontade e a capacitação técnica dos programadores para não incluírem lá métodos com comportamento ou atributos. Isso é o tipo de coisa que chamamos de “abordagem sujeita a erros”, pois aquele membro menos capacitado da equipe pode ir até lá e fazer caquinha.

O que está te complicando é que esse motivo é conceitual. A implementação dos conceitos de interface e classe abstrata é muito similar (para não dizer, idêntica, como no caso do C++). Você dificilmente vai ver no código mais do que uma simples palavra chave e, no máximo, algumas restrições de uso. Entretanto, os conceitos em si são muito diferentes e usar um ou outro tem consequências a longo prazo.

A palavra chave interface reforça uma promessa: a de que aquele compromisso é de comportamento, e continuará sendo de comportamento. Você vai notar que o desenvolvimento de software é basicamente formado de compromissos de diferentes tipos entre uma classe e outra e, deixa-los absolutamente claros e, preferencialmente, verificados pelo compilador, é o que torna os sistemas robustos.

P

ViniGodoy, obrigado pela resposta e pela paciência, vou aceitar o que você colocou.
Continuo com o pensamento de que tecnicamente eu posso usar uma classe abstrata para fazer o papel de uma interface, deixando de lado o fato de alguém poder implementar um método na classe abstrata, ou da ligação mais forte de herança que você comentou, pois isso são questões teóricas (de boas práticas), mas que não me impedem na prática, certo?
Claro que estas questões que você levantou estão corretíssimas, e eu defendo sim o uso de interfaces. Eu só queria tirar a prova na questão prática mesmo.

Valeu!

sergiotaborda

pedroe:
ViniGodoy, obrigado pela resposta e pela paciência, vou aceitar o que você colocou.
Continuo com o pensamento de que tecnicamente eu posso usar uma classe abstrata para fazer o papel de uma interface, deixando de lado o fato de alguém poder implementar um método na classe abstrata, ou da ligação mais forte de herança que você comentou, pois isso são questões teóricas (de boas práticas), mas que não me impedem na prática, certo?

Errado. Mas continue pensando assim e trabalhando assim. Quando um dia vc se ferrar ai vc vai entender porque as questão teóricas são mais importantes que a prática.

drsmachado

sergiotaborda:
pedroe:
ViniGodoy, obrigado pela resposta e pela paciência, vou aceitar o que você colocou.
Continuo com o pensamento de que tecnicamente eu posso usar uma classe abstrata para fazer o papel de uma interface, deixando de lado o fato de alguém poder implementar um método na classe abstrata, ou da ligação mais forte de herança que você comentou, pois isso são questões teóricas (de boas práticas), mas que não me impedem na prática, certo?

Errado. Mas continue pensando assim e trabalhando assim. Quando um dia vc se ferrar ai vc vai entender porque as questão teóricas são mais importantes que a prática.


Sérgio, esse discurso do pedroe é compreensível quando não se tem ainda uma experiência que garanta coisas como a necessidade de usar uma classe abstrata de terceiros que foi mal implementada e que seria super simples caso fosse uma interface.

ViniGodoy

… e a possibilidade de implementar várias interfaces…

Certo. Deixando de lado todas as diferenças, são iguais. :lol:

No caso, a ligação forte não é boa prática, é uma questão de projeto. É como decidir se você cria um filho ou usa composição. As duas podem, teoricamente, fazer a mesma coisa. Mas ambas implicam em consequências de projeto diferentes a longo prazo.

Todas as limitações das interfaces e a possibilidade de “herança múltipla” são para justamente reforçar esse conceito teórico. Em termos técnicos, não duvido que o compilador as trate como uma espécie de classes abstratas mesmo. Ou, como no caso do C++, elas efetivamente sejam classes abstratas.

Agora, é importante diferenciar entre a existência de um conceito e sua implementação. No C++, por exemplo, existe com templates uma forma curiosa de implementar o conceito de interfaces, que não envolve criar uma classe, ou sequer declarar a interface em lugar nenhum (exceto seu diagrama UML).

Você pode fazer um método assim:

template <typename T> public void soma(T[] v1, T[] v2, int size) { for (int i = 0; i < size; ++i) v1[i] += v2[i]; }

Não existe uma definição para “T” além dessa.

Então, onde está a interface nessa função? Está implicita.
Basicamente “T” pode ser qualquer coisa que você pudesse fornecer para a função, e que não desse erro de compilação.

Por exemplo, poderia ser dois arrays primitivos de int ou float. Note que esse código funcionaria perfeitamente com eles.
Poderia ser também dois vector (equivalente ao List, do java). No C++, o operador de [] é sobrecarregado num vector e, portanto, poderia ser usado nesse contexto.
Poderia ser também dois Vector2, de uma biblioteca matemática, como a que implementei na ForFun. Enfim, poderia ser qualquer coisa que tivesse os operadores de [] sobrecarregados, e que o resultado desses operadores fossem somáveis (inclusive 2 arrays de std::string, onde ele faria a concatenação de todos os elementos, já que a string, no C++, é mutável e suporta o +=).

Ou seja, a interface aqui está definida única e exclusivamente pelo comportamento, e não pela necessidade de uma classe dizer que “implementa uma interface”. Qualquer classe que o programador forneça para esse método, que se comporte como o código assume que se comporte, serve. Vê? É uma forma completamente diferente de se implementar exatamente o mesmo conceito.

A forma que se escolhe para implementar um conceito geralmente vai implicar em limitações da linguagem, ou a existência ou não de verificações do compilador, etc… Agora é importante compreender o conceito e o que ele representa em termos de projeto, pois a linguagem é só a forma que temos para expressar isso para o computador.

Rodrigo_Sasaki

Na prática pode até funcionar.

Nada impede você de iterar um array que contém o alfabeto, e invocar um método que retorna uma String via reflection pra formar o seu nome e imprimir em um System.out.print

Nada impede você de fazer um sistema onde a camada de controle da view, as regras de negócio e a persistência estão implementadas em uma classe só, no seu “Sistema.java”

Mas eu não recomendaria nada disso…

P

sergiotaborda, da pra ver que você possui dificuldade em compreender e interpretar textos, mas isso é normal pra maioria, infelizmente. Eu conheço o que é melhor em sentido de projeto, e sei da importância da interface. Eu abri este tópico única e exclusivamente para ter certeza que em termos prático não haveria diferenças. Se observares o primeiro post desse tópico, eu cito a questão de poder implementar várias interfaces, mas que gostaria de saber se havia alguma outra vantagem prática (de código mesmo).

… e a possibilidade de implementar várias interfaces…

Certo. Deixando de lado todas as diferenças, são iguais.

ViniGodoy, era exatamente isso que eu estava buscando como resposta. Não pensem que eu não entendi as vantagens de se usar interface, até porque eu já as conhecia. Deixando de lado questões de projeto, de pegar uma classe abstrata implementada por terceiros, etc e etc. O que me impediria (que seria um impasse de fato) eu meu próprio código, é isso o que eu estava buscando (mais uma vez dizendo que a questão de “herança múltipla” já era do meu conhecimento).

Obrigado a todos!

sergiotaborda

sergiotaborda, da pra ver que você possui dificuldade em compreender e interpretar textos, mas isso é normal pra maioria, infelizmente. Eu conheço o que é melhor em sentido de projeto, e sei da importância da interface. Eu abri este tópico única e exclusivamente para ter certeza que em termos prático não haveria diferenças. Se observares o primeiro post desse tópico, eu cito a questão de poder implementar várias interfaces, mas que gostaria de saber se havia alguma outra vantagem prática (de código mesmo).

Vc faz me lembrar aquele cara que esta se afogando e pediu que Deus o salvasse. Ai chega um barco e quer salvar o cara, mas o cara responde “não obrigado, Deus vai-me salvar” e isso acontece várias vezes até que Deus perde a paciencia e fala "Cara, deixa de ser chato, já te mandei 3 barcos "

Existe sim diferença teórica e prática entre classe abstrata e interface. Se não existisse, não precisaria de dois contrutos.
Vc consegue fazer quase tudo o que faz com uma, com o que faz com outra, mas não tudo.

Se vc colocar num diagrama de Vernn o que dá para fazer com um e com outro são conjuntos dijuntos.
Existe uma intersecção não vazia. Sim existe, mas isso é inconsequente.

Ai vc vem com essa de "Eu abri este tópico única e exclusivamente para ter certeza que em termos prático não haveria diferenças. " e todo o mundo lhe disse que ha diferenças. Tanto práticas quanto teóricas. Mas vc insiste em querer que lhe digam que não , que não ha diferença.

[/quote]

É. Vc estava buscando. Mas a frase é sarcástica e vc não entendeu isso. Se “Deixando de lado todas as diferenças” são iguais, quer dizer que ha diferenças.É como dizer que “O homem e a mulher, deixando de lado todas as diferenças, são iguais.” Entendeu ?

Pior de tudo é que vc ainda afirma que sabe que existem diferenças e quais elas são, mas mesmo assim vc insiste em quere que lhe digam que não diferenças ? :shock:

Vai ver eu estou louco e realmente não sei ler, mas esta conversa me parece conversa de surdos. Vc não quer ouvir a resposta real.
Então tá, Não existe diferença nenhuma, e como eu disse antes, continue pensando assim. Quando cair a ficha que todos os barcos passaram, não venha chorar que ninguém o salvou.

sergiotaborda

drsmachado:
sergiotaborda:
pedroe:
ViniGodoy, obrigado pela resposta e pela paciência, vou aceitar o que você colocou.
Continuo com o pensamento de que tecnicamente eu posso usar uma classe abstrata para fazer o papel de uma interface, deixando de lado o fato de alguém poder implementar um método na classe abstrata, ou da ligação mais forte de herança que você comentou, pois isso são questões teóricas (de boas práticas), mas que não me impedem na prática, certo?

Errado. Mas continue pensando assim e trabalhando assim. Quando um dia vc se ferrar ai vc vai entender porque as questão teóricas são mais importantes que a prática.


Sérgio, esse discurso do pedroe é compreensível quando não se tem ainda uma experiência que garanta coisas como a necessidade de usar uma classe abstrata de terceiros que foi mal implementada e que seria super simples caso fosse uma interface.

Quando vc está na faculdade e o professor lhe diz algo, ou quando seu pai lhe diz algo, vc pode simplesmente não acreditar. Mas vc estará sendo louco se achar que eles estão mentindo. Uma coisa é vc não ter experiencia e não entender o que lhe dizer, outra é não querer entender e outra pior é não querer aceitar. Se a pessoa não aceita o que é óbvio ela continuará vivendo, mas com menos qualidade do que poderia. Me lembra o velho problema do pessoa que não quer acreditar que MVC não é separação em camadas. Existe um limite para o como e de quantas formas podemos explicar o óvibo. O resto advém da aceitação e o resto advém da experiancia.

Eu sei que ha pouco experiencia envolvida, mas é mais do que isso, é uma teimosia estranha em não aceitar o que todo o mundo já falou.
Passar a mão na cabeça e dizer que sim, é isso mesmo, é paternalismo : não estamos aqui para ser paternalistas. Estamos aqui para tentar transmitir conhecimento. Mais do que isso, transmitir valores.

J

Olás

Mesmo sabendo bem menos e sem querer polemizar com ninguém, apenas estou me esforçando para entender tudo o que foi dito, tento dar meu pítaco.
O trecho abaixo foi tirado dos documentos da Oracle sobre o tema em questão. É longo, mas para os neófitos como eu , acredito que será de interesse ler.

Esse texto tenta responder as seguintes perguntas do pedroe


Qual a diferença entre as duas implementações?
Em ambas eu defino um contrato a ser seguido. Se eu criar uma classe que só possua métodos abstratos, não irei estar criando uma espécie de interface?

O texto traduzido:

Interfaces

Há uma série de situações em engenharia de software quando é importante para diferentes grupos de programadores concordar com um “contrato” que indica como seu software interage com os demais. Cada grupo deve ser capaz de escrever seu código, sem qualquer conhecimento de como o código do outro grupo está escrito. De um modo geral, as interfaces são contratos.

Por exemplo, imagine uma sociedade futurista, onde carros robóticos controlados por computador transportam passageiros pelas ruas da cidade sem um operador humano. Os fabricantes de automóveis escreverão software (Java, é claro) que opera o automóvel para que ele pare, de a partida, acelere, vire à esquerda, e assim por diante. Outro grupo industrial, fabricantes de instrumentos eletrônicos de orientação, farão sistemas de computadores que recebem dados de GPS para se pocisionar e as condições de tráfego para dirigir o carro com essas informações.

Os fabricantes de automóveis, então, devem publicar uma interface padrão dessa indústria que explica em detalhes o que métodos chamados podem fazer para movimentar o carro (qualquer carro, de qualquer fabricante). Os fabricantes poderão então escrever softwares que chamarão os métodos descritos na interface para comandar o carro. Nenhum grupo industrial precisa saber como o software do outro grupo é implementado. De facto, cada grupo considera seu software altamente proprietário e se reserva o direito de modificá-lo a qualquer momento, enquanto continua aderindo a interface publicada.

No exemplo do carro robótico acima, serão os fabricantes de automóveis que irão implementar a interface. A implementação da Chevrolet será substancialmente diferente da Toyota, é claro, mas ambos os fabricantes aderem à mesma interface. Os fabricantes de orientação, que são os clientes da interface, irão construir sistemas que utilizam os dados de GPS sobre a localização de um carro, mapas digitais de rua, e dados de tráfego para dirigir o carro. Ao fazer isso, os sistemas de orientação irão chamar os métodos de interface: transformar, pistas de mudança, de freio, acelerar, e assim por diante.

Interfaces e herança múltipla

Interfaces tem outro papel muito importante na linguagem de programação Java. Interfaces não fazem parte da hierarquia de classes, apesar de trabalharem em conjunto com as classes. A linguagem de programação Java não permite herança múltipla, mas as interfaces fornecem uma alternativa.

Em Java, uma classe só pode herdar parâmetros e métodos de apenas uma classe, mas pode implementar mais de uma interface. Portanto, os objetos podem ter vários tipos: o tipo de sua própria classe e os tipos de todas as interfaces que ela implementa. Isto significa que se uma variável é declarada para ser o tipo de uma interface, o seu valor pode fazer referência a qualquer objeto que é instanciado a partir de qualquer classe que implementa a interface.

Classes abstratas vs Interfaces

Ao contrário de interfaces, classes abstratas podem conter campos que não são static e final, e podem conter métodos implementados. Tais classes abstratas são semelhantes às interfaces, exceto que eles fornecem uma implementação parcial, deixando à subclasse concluir a implementação. Se uma classe abstrata contém apenas declarações de métodos abstratos, deve ser declarado como uma interface em vez de classe abstrata.

Multiplas interfaces podem ser implementadas por uma classe em qualquer lugar na hierarquia de classes, estejam ou não relacionadas umas com as outras.

Em comparação, classes abstratas são mais comumente subclasses que compartilham pedaços de implementações. Uma única classe abstrata é uma subclasse de classes semelhantes que têm muito em comum (as partes implementadas da classe abstrata), mas também têm algumas diferenças (os métodos abstratos).

Pelo exposto, fica claro que a interface java tem duas funções, servir como um “interface pública” para determinadas implementações de software e permitir que as classes possam ter herança múltipla.

Pelo exposto, no que concerne ao papel de “interface pública”, não há como tecnicamente fazer uma classe abstrata agir desse modo. Para isso ela teria que ser a superclasse de todas as demais classes, o que não permitiria implementar nenhuma “interface pública”! Pois todos os métodos abstratos serão implementados nas subclasses e estas não se comunicarão. [Por favor, digam se o meu arrazoado está certo]

Pelo que entendi, a única possibilidade técnica, como o pedroe tentava descobrir, de fazer uma classe abstrata funcionar como uma interface está exatamente no papal de suprir a herança múltipla. Essa “possibilidade técnica” é apenas no sentido de alguém que não tá afim de fazer nada direito e resolve escreve tudo em uma classe abstrata. Mas se fizer isso, não dará erros e o aplicativo rodará. [idem]

Escrevi sobre isso não desprezando nenhuma das argumentações e explicações dadas, apenas procurei encontrar o meu entendimento e expus aqui para que o avaliem. Nada do que foi escrito aqui tem a intenção de substituir o que já foi dito. É apenas um exercício.
Abs.

G

joagostini:
Pelo que entendi, a única possibilidade técnica, como o pedroe tentava descobrir, de fazer uma classe abstrata funcionar como uma interface está exatamente no papal de suprir a herança múltipla.

mas o “papel de herança múltipla”, é exatamente o q a classe abstrata não poderá suprir.

pelo q eu entendo, essa é exatamente uma coisa q só se consegue no java com uso de interfaces.

não só no java, mas tb na maioria das outra linguagens.

J

GilsonNunes

O meu raciocínio é o seguinte.
Imagine uma classe chamada Casa, onde se descreve todos os cômodos de uma casa em termos de suas dimensões.
Crio uma classe Empreiteiro que estende casa, e que com base nas dimensões calcula quanto tempo que irá demorar para construir a casa.
O dono das classes decidiu, que além do tempo, quer saber o custo de cada cômodo.
Em vez de criar uma interface Custo implementando-a em Empreiteiro, ele faz de Casa uma classe abstrata e declara um método abstrato quantoCusta();.
Em Empreiteiro ele implementa o método para cada cômodo.
Nesse momento é como se fosse uma herança de outra classe, pois o cidadão pois os dois na mesma classe.
É assim que entendi a possibilidade de usar uma classe abstrata como se fosse uma interface.

G

joagostini:
GilsonNunes

O meu raciocínio é o seguinte.
Imagine uma classe chamada Casa, onde se descreve todos os cômodos de uma casa em termos de suas dimensões.
Crio uma classe Empreiteiro que estende casa, e que com base nas dimensões calcula quanto tempo que irá demorar para construir a casa.
O dono das classes decidiu, que além do tempo, quer saber o custo de cada cômodo.
Em vez de criar uma interface Custo implementando-a em Empreiteiro, ele faz de Casa uma classe abstrata e declara um método abstrato quantoCusta();.
Em Empreiteiro ele implementa o método para cada cômodo.
Nesse momento é como se fosse uma herança de outra classe, pois o cidadão pois os dois na mesma classe.
É assim que entendi a possibilidade de usar uma classe abstrata como se fosse uma interface.

mas eu não consigo ver o q isso tem a ver com múltipla herança.

J

Gilson

Talvez seja melhor que vc diga porque não seria a simulação de múltipla herança.
Já que o que descrevi nada mais é que como se pode usar uma classe abstrata, que no caso ao invés de assinar um método abstrato correlato aos métodos declarados da classe, traz consigo elementos do que seria uma outra classe.

G

joagostini:
Gilson

Talvez seja melhor que vc diga porque não seria a simulação de múltipla herança.
Já que o que descrevi nada mais é que como se pode usar uma classe abstrata, que no caso ao invés de assinar um método abstrato correlato aos métodos declarados da classe, traz consigo elementos do que seria uma outra classe.

multipla herança, seria se um objeto Empreiteiro precisasse se passar por Custo.
o fato de agora ele ter um metodo com nome e assinatura igual ao da classe Custo, não significa q o compilador vai achar q ele é um Custo.

onde se pede um Custo, aceita um Custo ou seus derivados, no caso de Custo ser classe;
ou um q implemente, caso Custo seja interface (aki é q dá vida à “múltipla herança”, já q o tal poderia herdar de qq coisa).

J

GilsonNunes:

multipla herança, seria se um objeto Empreiteiro precisasse se passar por Custo.
o fato de agora ele ter um metodo com nome e assinatura igual ao da classe Custo, não significa q o compilador vai achar q ele é um Custo.

onde se pede um Custo, aceita um Custo ou seus derivados, no caso de Custo ser classe;
ou um q implemente, caso Custo seja interface (aki é q dá vida à “múltipla herança”, já q o tal poderia herdar de qq coisa).

Olha, acho que vc está definindo outra coisa.
Peguei esta definição de herança aqui http://www.dca.fee.unicamp.br/cursos/PooJava/heranca/index.html

Herança
Herança é um mecanismo que permite que características comuns a diversas classes sejam fatoradas em uma classe base, ou superclasse. A partir de uma classe base, outras classes podem ser especificadas. Cada classe derivada ou subclasse apresenta as características (estrutura e métodos) da classe base e acrescenta a elas o que for definido de particularidade para ela.

Nessa definição não há referência a que um objeto se passe por outro, mas que um objeto herda estrutura e métodos da super classe e acrescenta os seus próprios. Dessa forma, Empreiteiro dá origem ao objeto empreiteiro que usa, entre outros, métodos do objeto casa para realizar as suas funções de empreiteiro. Analogia com seres humanos: herdei características dos meus pais, mas não sou nem um e nem outro, sou eu apenas com herança.
O que pensei em base ao que pedroe questionva seria o uso errado de uma classe abstrata inserindo nela parâmetros e métodos de dois objetos diferentes. Um com métodos descritos, outra com métodos abstratos, que seriam definidos na subclasse. Isso fingiria que a subclasse herdaria métodos de “dois objetos diferentes”.

P

sergiotaborda, vamos lá então, hehe.

Seguinte: imagine que tenho uma classe abstrata apenas com métodos abstratos. Essa classe eu estou implementando para mim, nunca ninguém além de mim irá utilizá-la. Eu nunca vou disponibilizar essa classe em alguma biblioteca para ser usada por outros, e também nunca vou deixar algum programador mexer nessa classe e implementar algum método, ou fazer alguma coisa errada. Resumindo, eu sei que essa classe só deve possuir métodos abstratos, e ela permanecerá assim. Neste cenário, qual a vantagem de utilizar interface?
Tirando o fato de que com interface eu posso ter uma “herança múltipla” (implementando várias interfaces).

É. Vc estava buscando. Mas a frase é sarcástica e vc não entendeu isso. Se “Deixando de lado todas as diferenças” são iguais, quer dizer que ha diferenças.É como dizer que “O homem e a mulher, deixando de lado todas as diferenças, são iguais.” Entendeu ?

Pior de tudo é que vc ainda afirma que sabe que existem diferenças e quais elas são, mas mesmo assim vc insiste em quere que lhe digam que não diferenças ?

Cara, as diferenças que eu disse que conheço são teóricas (e.g. melhores práticas de se programar, pensando no lado de projeto, de como ficará o visual do código, etc) mas não limitações práticas! Entenda isso por favor. Ninguém até agora me deu um exemplo do tipo “cara, se você tiver que fazer isto: xxx… você só conseguirá fazer com interface”.

O ViniGodoy não me deu uma resposta sarcástica ao meu ver. E se deu o problema é dele, com todo o respeito. Pense no seguinte: se você herdar uma classe abstrata, não poderá herdar outra. Se usar interface ao invés da classe abstrata, poderá implementar diversas interfaces. Isto é uma limitação técnica quando se usa classes abstratas!.
É isso o que eu quero. Porém este exemplo eu já conheço e citei no primeiro post. Eu só quero ver se existe outro exemplo como este.

Eu tenho muita experiência em Java meu caro, programo há anos, e isso não quer dizer que eu seja um guru. Essa dúvida só me surgiu agora.
E se a “classe de terceiros que foi mal implementada” tivesse sido bem implementada? O que eu quero deixar de lado é esta questão de “pode ser, pode não ser”. Eu quero a limitação técnica. Eu não estou dizendo que se ninguém me der uma resposta pra essa pergunta eu vou passar a só usar classe abstrata. Eu defendo interface! Pelos termos já citados de projeto, de que lá na frente pode surgiu algum problema. Mas quero por curiosidade saber da questão técnica, prática.

Existe sim diferença teórica e prática entre classe abstrata e interface. Se não existisse, não precisaria de dois contrutos.
Vc consegue fazer quase tudo o que faz com uma, com o que faz com outra, mas não tudo.

O que não posso fazer então?

sergiotaborda

pedroe:

O que não posso fazer então?

Não vou repetir o que já foi dito, mas resumindo

Interface - I

Define um contrato publico
Não define Identidade (É-UM)
Apenas define contratos públicos.

Classe Abstrata - A

Define um contrato publico
Define Identidade (É-UM)
Não apenas define contratos públicos. Podendo definir contratos em qualquer nível de visibilidade (publico, protegido ou de pacote)

I intersecção A

Define um contrato publico. É só isto que têm em comum. Nada mais.

O seu exemplo de uma classe abstrata que só vc usar, etc, etc… é vazio. OO não está nem ai para o programador que usa a classe. Ela está ai para como as outras classes a usam.
Se vc define uma classe puramente abstrata com apenas metodos publico vc não tem o mesmo efeito que uma interface. Está claro isto ? Porquê ? Porque ao definir o conceito como uma classe abstrata vc está dizendo que aquele conceito é a responsabilidade primária da classe. Exemplo do Calendar que é uma classe abstrata. O que é Calendar não é mais coisa nenhuma. Atenção ao verbo ser. A classe abstrata define a relação É-UM automaticamente. Não tem como vc evitar isso. Portanto ela é intrinsecamente diferente de uma interface que nunca conseguirá definir esta relação.

Ambas as opções são diferentes intrinsecamente. Até o bytecode é diferente.

Pode parecer , à primeira vista, que uma classe puramente abstrata com métodos públicos é equivalente a uma interface. Simplesmente não é.

Isto

public abstract  class XPTO {

}

e isto,

public interface XPTO {

}

são equivalentes ? Repare que não ha nenhum método…

Não. não são equivalentes.
Não sei como lhe explicar isso melhor senão dizendo que uma define relação É-UM e a outra não.

Se elas não são equivalentes quando vazias, por maioria de razão, não o serão quando tiverem métodos - não importa quais. Elas já são diferentes à partida.
Ao tomar a decisão entre uma e outra ha um trade-off, portanto não ha equivalência.

A interface sempre têm vantagem porque ela pode ser a raiz de uma hierarquia ou não. A classe abstrata sempre é.
Eu , por exemplo, sempre defino meus conceitos OO como interfaces. E só mais tarde, se descobrir que precisa forçar a identidade desde o inicio que mudo para abstrato. Normalmente eu definio o conceito como interface porque me permite programar para a interface sem precisar pensar como será implementado. Depois eu crio uma classe abstrata se a interface tem muitos métodos comuns às implementações. Se isso foi muito forte, então significa que o conceito por si mesmo me força a considerar uma herança forte , e nesse momento eu renomeio a classe abstrata para o nome da interface e removo a interface. Mas isto é raro. A estrutura Interface A <- class abstrata AbstractA <-- os outros costuma funcionar muito bem (não é por acaso que é a base da API de collections)

Bom, se ainda não ficou claro, alguém que explique. Eu não tenho mais palavras.

Criado 8 de agosto de 2012
Ultima resposta 17 de ago. de 2012
Respostas 45
Participantes 15