Classe abstrata vs interface em Java


87

Foi-me feito uma pergunta, gostaria que a minha resposta fosse revista aqui.

P: Em qual cenário é mais apropriado estender uma classe abstrata em vez de implementar a (s) interface (s)?

R: Se estivermos usando o padrão de design do método de modelo.

Estou correcto ?

Lamento se não fui capaz de colocar a questão claramente.
Eu sei a diferença básica entre classe abstrata e interface.

1) usar classe abstrata quando o requisito é tal que precisamos implementar a mesma funcionalidade em cada subclasse para uma operação específica (implementar o método) e funcionalidade diferente para algumas outras operações (apenas assinaturas de método)

2) use a interface se precisar colocar a assinatura para ser a mesma (e a implementação diferente) para que possa cumprir com a implementação da interface

3) podemos estender no máximo uma classe abstrata, mas podemos implementar mais de uma interface

Reiterando a pergunta: Existem outros cenários, além dos mencionados acima, onde especificamente precisamos usar a classe abstrata (veja se o modelo de design do método de modelo é conceitualmente baseado apenas nisso)?

Interface vs. classe abstrata

A escolha entre os dois realmente depende do que você deseja fazer, mas, felizmente para nós, Erich Gamma pode nos ajudar um pouco.

Como sempre, há uma compensação, uma interface oferece liberdade em relação à classe base, uma classe abstrata oferece a liberdade de adicionar novos métodos posteriormente . - Erich Gamma

Você não pode ir e mudar uma interface sem ter que mudar muitas outras coisas em seu código, então a única maneira de evitar isso seria criar uma interface totalmente nova, o que nem sempre é uma coisa boa.

Abstract classesdeve ser usado principalmente para objetos intimamente relacionados. Interfacessão melhores em fornecer funcionalidade comum para classes não relacionadas.




Isso não é duplicado. OP quer saber quando estender a classe abstrata em vez de implementar uma interface. Ele não quer saber quando escrever uma classe ou interface abstrata. Sua classe abstrata e interface já estão escritas. Hd quer saber se deve estender ou implementar.
Shiplu Mokaddim

1
@ shiplu.mokadd.im Isso é uma distinção sem diferença. Você não pode usar uma classe abstrata sem estendê-la. Suas críticas aqui parecem completamente inúteis.
Marquês de Lorne

Respostas:


86

Quando usar interfaces

Uma interface permite que alguém comece do zero para implementar sua interface ou implementar sua interface em algum outro código cujo propósito original ou principal seja bem diferente de sua interface. Para eles, sua interface é apenas incidental, algo que deve ser adicionado ao código deles para poder usar seu pacote. A desvantagem é que todos os métodos da interface devem ser públicos. Você pode não querer expor tudo.

Quando usar classes abstratas

Uma classe abstrata, em contraste, fornece mais estrutura. Geralmente define algumas implementações padrão e fornece algumas ferramentas úteis para uma implementação completa. O problema é que o código que o usa deve usar sua classe como base. Isso pode ser altamente inconveniente se os outros programadores que desejam usar seu pacote já desenvolveram sua própria hierarquia de classes independentemente. Em Java, uma classe pode herdar de apenas uma classe base.

Quando usar ambos

Você pode oferecer o melhor dos dois mundos, uma interface e uma classe abstrata. Os implementadores podem ignorar sua classe abstrata, se quiserem. A única desvantagem de fazer isso é chamar métodos por meio de seu nome de interface é um pouco mais lento do que chamá-los por meio de seu nome de classe abstrato.


Acho que OP quer saber quando estender a classe abstrata em vez de implementar uma interface
Shiplu Mokaddim

@ shiplu.mokadd.im Na verdade, o OP fez uma pergunta muito específica, para a qual a resposta é 'sim' ou 'não'.
Marquês de Lorne

4
Você está certo. Mas em SO respondemos sim / não com a explicação adequada.
Shiplu Mokaddim

1
@ shiplu.mokadd.im Não vejo como isso lhe dá licença para formular erroneamente a pergunta dele.
Marquês de Lorne

Apenas com base nesta única afirmação If we are using template method design patternNão podemos dizer YESouNO
DivineDesert

31

reiterando a questão: há qualquer outro cenário além dos mencionados acima, onde especificamente precisamos usar a classe abstrata (veja-se que o padrão de design do método de modelo é conceitualmente baseado apenas nisso)

Sim, se você usar JAXB. Não gosta de interfaces. Você deve usar classes abstratas ou contornar essa limitação com genéricos.

De uma postagem de blog pessoal :

Interface:

  1. Uma classe pode implementar várias interfaces
  2. Uma interface não pode fornecer nenhum código
  3. Uma interface só pode definir constantes finais estáticas públicas
  4. Uma interface não pode definir variáveis ​​de instância
  5. Adicionar um novo método tem efeito cascata na implementação de classes (manutenção de design)
  6. JAXB não pode lidar com interfaces
  7. Uma interface não pode estender ou implementar uma classe abstrata
  8. Todos os métodos de interface são públicos

Em geral, as interfaces devem ser usadas para definir contratos (o que deve ser alcançado, não como fazê-lo).

Classe abstrata:

  1. Uma classe pode estender no máximo uma classe abstrata
  2. Uma classe abstrata pode conter código
  3. Uma classe abstrata pode definir constantes estáticas e de instância (final)
  4. Uma classe abstrata pode definir variáveis ​​de instância
  5. A modificação do código da classe abstrata existente tem efeito cascata na extensão das classes (manutenção da implementação)
  6. Adicionar um novo método a uma classe abstrata não tem efeito cascata na extensão de classes
  7. Uma classe abstrata pode implementar uma interface
  8. Classes abstratas podem implementar métodos privados e protegidos

Classes abstratas devem ser usadas para implementação (parcial). Eles podem ser um meio de restringir a maneira como os contratos de API devem ser implementados.


3
No Java 8 para interface # 8, você também pode ter métodos defaulte static.
Usuário iniciante


9

Há muitas respostas boas aqui, mas geralmente acho que usar AMBAS as interfaces e classes abstratas é o melhor caminho. Considere este exemplo inventado:

Você é um desenvolvedor de software em um banco de investimento e precisa construir um sistema que coloque pedidos em um mercado. Sua interface captura a ideia mais geral do que um sistema de negociação faz ,

1) Trading system places orders
2) Trading system receives acknowledgements

e pode ser capturado em uma interface, ITradeSystem

public interface ITradeSystem{

     public void placeOrder(IOrder order);
     public void ackOrder(IOrder order);

}

Agora, os engenheiros que trabalham no balcão de vendas e em outras linhas de negócios podem começar a interagir com seu sistema para adicionar a funcionalidade de colocação de pedidos aos aplicativos existentes. E você ainda nem começou a construir! Este é o poder das interfaces.

Então você vai em frente e constrói o sistema para os corretores de ações ; eles ouviram dizer que seu sistema possui um recurso para localizar ações baratas e estão ansiosos para experimentá-lo! Você captura esse comportamento em um método chamado findGoodDeals(), mas também percebe que há um monte de coisas complicadas envolvidas na conexão com os mercados. Por exemplo, você deve abrir um SocketChannel,

public class StockTradeSystem implements ITradeSystem{    

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

As implementações concretas vão ter muitos desses métodos confusos, como connectToMarket(), mas findGoodDeals()é tudo com que os comerciantes realmente se preocupam.

Agora é aqui que as classes abstratas entram em jogo. Seu chefe informa que os negociantes de moeda também desejam usar seu sistema. E olhando para os mercados de câmbio, você vê que o encanamento é quase idêntico ao dos mercados de ações. Na verdade, connectToMarket()podem ser reutilizados literalmente para se conectar aos mercados de câmbio. No entanto, findGoodDeals()é um conceito muito diferente na arena monetária. Portanto, antes de passar a base de código para o garoto mago do câmbio do outro lado do oceano, você primeiro refatora em uma abstractclasse, deixando não findGoodDeals()implementado

public abstract class ABCTradeSystem implements ITradeSystem{    

    public abstract void findGoodDeals();

    @Override 
    public void placeOrder(IOrder order);
         getMarket().place(order);

    @Override 
    public void ackOrder(IOrder order);
         System.out.println("Order received" + order);    

    private void connectToMarket();
       SocketChannel sock = Socket.open();
       sock.bind(marketAddress); 
       <LOTS MORE MESSY CODE>
    }

Seu sistema de negociação de ações implementa findGoodDeals()como você já definiu,

public class StockTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       deals = <apply magic wizardry>
       System.out.println("The best stocks to buy are: " + deals);
    }

mas agora o garoto prodígio do FX pode construir seu sistema simplesmente fornecendo uma implementação de findGoodDeals()para moedas; ela não tem que reimplementar as conexões de soquete ou mesmo os métodos de interface!

public class CurrencyTradeSystem extends ABCTradeSystem{    

    public void findGoodDeals();
       ccys = <Genius stuff to find undervalued currencies>
       System.out.println("The best FX spot rates are: " + ccys);
    }

A programação para uma interface é poderosa, mas aplicativos semelhantes geralmente reimplementam métodos de maneiras quase idênticas. O uso de uma classe abstrata evita reimplmentações, enquanto preserva o poder da interface.

Nota: pode-se perguntar por que findGreatDeals()não faz parte da interface. Lembre-se de que a interface define os componentes mais gerais de um sistema de negociação. Outro engenheiro pode desenvolver um sistema de negociação COMPLETAMENTE DIFERENTE, onde eles não se importam em encontrar bons negócios. A interface garante que o balcão de vendas também possa interagir com o sistema deles, portanto, é preferível não confundir sua interface com conceitos de aplicativos como "ótimas ofertas".


6

O que você deve usar, classes abstratas ou interfaces?

Considere o uso de classes abstratas se alguma dessas instruções se aplicar ao seu caso de uso:

Você deseja compartilhar código entre várias classes estreitamente relacionadas.

Você espera que as classes que estendem sua classe abstrata tenham muitos métodos ou campos comuns ou exijam modificadores de acesso diferentes de público (como protected e private).

Você deseja declarar campos não estáticos ou não finais. Isso permite definir métodos que podem acessar e modificar o estado do objeto ao qual pertencem.

Considere o uso de interfaces se alguma dessas instruções se aplicar ao seu caso de uso:

Você espera que classes não relacionadas implementem sua interface. Por exemplo, as interfaces Comparable e Cloneable são implementadas por muitas classes não relacionadas.

Você deseja especificar o comportamento de um determinado tipo de dados, mas não se preocupa com quem implementa seu comportamento.

Você deseja tirar proveito da herança múltipla de tipo.

http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html


4

As coisas mudaram muito nos últimos três anos com a adição de novos recursos para fazer a interface com o lançamento do Java 8.

Na página de documentação do oracle na interface:

Uma interface é um tipo de referência, semelhante a uma classe, que pode conter apenas constantes, assinaturas de método, métodos padrão, métodos estáticos e tipos aninhados. Corpos de método existem apenas para métodos padrão e métodos estáticos.

Como você citou em sua pergunta, a classe abstrata é mais adequada para o padrão de método de modelo em que você deve criar o esqueleto. A interface não pode ser usada aqui.

Mais uma consideração para preferir a classe abstrata à interface:

Você não tem implementação na classe base e apenas as subclasses precisam definir sua própria implementação. Você precisa de uma classe abstrata em vez de uma interface, pois deseja compartilhar o estado com as subclasses.

A classe abstrata estabelece "é uma" relação entre classes relacionadas e a interface fornece "uma" capacidade entre classes não relacionadas .


Com relação à segunda parte de sua pergunta, que é válida para a maioria das linguagens de programação, incluindo java antes do lançamento de java-8

Como sempre, há uma compensação, uma interface oferece liberdade em relação à classe base, uma classe abstrata oferece a liberdade de adicionar novos métodos posteriormente. - Erich Gamma

Você não pode ir e mudar uma interface sem ter que mudar muitas outras coisas em seu código

Se você preferir a classe abstrata para fazer a interface com as duas considerações acima, deve repensar agora, pois os métodos padrão adicionaram recursos poderosos às interfaces.

Os métodos padrão permitem adicionar novas funcionalidades às interfaces de suas bibliotecas e garantir compatibilidade binária com código escrito para versões mais antigas dessas interfaces.

Para selecionar um deles entre interface e classe abstrata, a página de documentação do Oracle cita que:

As classes abstratas são semelhantes às interfaces. Você não pode instanciá-los e eles podem conter uma combinação de métodos declarados com ou sem uma implementação. No entanto, com classes abstratas, você pode declarar campos que não são estáticos e finais e definir métodos concretos públicos, protegidos e privados.

Com interfaces, todos os campos são automaticamente públicos, estáticos e finais, e todos os métodos que você declara ou define (como métodos padrão) são públicos. Além disso, você pode estender apenas uma classe, seja ela abstrata ou não, enquanto você pode implementar qualquer número de interfaces.

Consulte essas questões relacionadas para obter mais detalhes:

Interface vs classe abstrata (OO geral)

Como devo ter explicado a diferença entre uma interface e uma classe abstrata?

Em resumo: o equilíbrio está se inclinando mais para as interfaces agora .

Existem outros cenários, além dos mencionados acima, onde especificamente precisamos usar a classe abstrata (veja se o padrão de design do método de modelo é conceitualmente baseado apenas nisso)?

Alguns padrões de projeto usam classes abstratas (sobre interfaces) além do padrão de método Template.

Padrões de criação:

Abstract_factory_pattern

Padrões estruturais:

Decorator_pattern

Padrões comportamentais:

Mediator_pattern


Isto: "A classe abstrata estabelece" é uma "relação entre classes relacionadas e fornece a interface" tem uma "capacidade entre classes não relacionadas."
Gabriel

3

Você não está correto. Existem muitos cenários. Simplesmente não é possível reduzi-lo a uma única regra de 8 palavras.


1
A menos que você seja vago como; Use uma interface sempre que puder;)
Peter Lawrey

@PeterLawrey Sim, não deixe que argumentos circulares atrasem você ;-)
Marquês de Lorne

Afinal, isso é "estouro de pilha". ;) Meu ponto é que se você pode usar a interface mais simples, faça-o. Caso contrário, você não tem escolha a não ser usar uma classe abstrata. Não vejo isso como muito complicado.
Peter Lawrey

Eu acho que você poderia fornecer uma ideia mais construtiva. como falar sobre alguns cenários representativos /
Adams.H

3

A resposta mais curta é estender a classe abstrata quando algumas das funcionalidades que você procura já estiverem implementadas nela.

Se você implementar a interface, terá que implementar todos os métodos. Mas, para a classe abstrata, o número de métodos que você precisa implementar pode ser menor.

No padrão de design de modelo , deve haver um comportamento definido. Este comportamento depende de outros métodos abstratos. Ao criar uma subclasse e definir esses métodos, você realmente define o comportamento principal. O comportamento subjacente não pode ser em uma interface, pois a interface não define nada, apenas declara. Portanto, um padrão de design de modelo sempre vem com uma classe abstrata. Se você quiser manter o fluxo do comportamento intacto, deve estender a classe abstrata, mas não sobrescrever o comportamento principal.


Referência adicional para Pure Virtual Function adicionará mais insights sobre Convergence of Abstract Class & Interface , Pure virtual functions can also be used where the method declarations are being used to define an interface - similar to what the interface keyword in Java explicitly specifies. In such a use, derived classes will supply all implementations. In such a design pattern, the abstract class which serves as an interface will contain only pure virtual functions, but no data members or ordinary methods. Part (1/2)
Abhijeet

Parte (2/2) Divergência de classe abstrata e interface é explicada pela última linha acima no data members or ordinary methods[em Classe abstrata].
Abhijeet

3

Na minha opinião, a diferença básica é que an interface can't contain non abstract methods while an abstract class can . Portanto, se as subclasses compartilham um comportamento comum, esse comportamento pode ser implementado na superclasse e, portanto, herdado nas subclasses

Também citei o seguinte do livro "software architecture design ppatterns in java"

"Na linguagem de programação Java, não há suporte para herança múltipla. Isso significa que uma classe pode herdar apenas de uma única classe. Portanto, a herança deve ser usada apenas quando for absolutamente necessário. Sempre que possível, os métodos que denotam o comportamento comum devem ser declarados em a forma de uma interface Java a ser implementada por diferentes classes de implementadores. Mas as interfaces sofrem com a limitação de não poderem fornecer implementações de métodos. Isso significa que cada implementador de uma interface deve implementar explicitamente todos os métodos declarados em uma interface, mesmo quando alguns deles os métodos representam a parte invariável da funcionalidade e têm exatamente a mesma implementação em todas as classes do implementador, o que leva a um código redundante.O exemplo a seguir demonstra como o padrão Abstract Parent Class pode ser usado em tais casos sem a necessidade de implementações de métodos redundantes. "


2

As classes abstratas são diferentes das interfaces em dois aspectos importantes

  • eles fornecem implementação padrão para métodos escolhidos (que é coberto por sua resposta)
  • classes abstratas podem ter estado (variáveis ​​de instância) - então esta é mais uma situação em que você deseja usá-las no lugar de interfaces

Gostaria de concluir que as interfaces podem ter variáveis, mas são, por padrão, finais.
Tomasz Mularczyk

1

Esta é uma boa pergunta. Os dois não são semelhantes, mas podem ser usados ​​pelo mesmo motivo, como uma reescrita. Ao criar é melhor usar a Interface. Quando se trata de aula, é bom para depuração.


0

Abstract classes should be extended when you want to some common behavior to get extended. A superclasse Abstract terá o comportamento comum e definirá o método abstrato / comportamento específico que as subclasses devem implementar.

Interfaces allows you to change the implementation anytime allowing the interface to be intact.


0

Este é o meu entendimento, espero que isso ajude

Classes abstratas:

  1. Pode ter variáveis ​​de membro que são herdadas (não pode ser feito em interfaces)
  2. Pode ter construtores (interfaces não podem)
  3. Seus métodos podem ter qualquer visibilidade (ou seja: privado, protegido, etc - enquanto todos os métodos de interface são públicos)
  4. Pode ter métodos definidos (métodos com uma implementação)

Interfaces:

  1. Pode ter variáveis, mas são todas variáveis ​​finais estáticas públicas
    • valores constantes que nunca mudam com um escopo estático
    • variáveis ​​não estáticas requerem uma instância, e você não pode instanciar uma interface
  2. Todos os métodos são abstratos (nenhum código em métodos abstratos)
    • todo o código tem que ser realmente escrito na classe que implementa a interface particular

0

Uso de resumo e interface:

Um tem "É-um-relacionamento" e outro tem "Tem-um-relacionamento"

As propriedades padrão foram definidas em abstrato e propriedades extras podem ser expressas por meio da interface.

Exemplo: -> Nos seres humanos temos algumas propriedades padrão que são comer, dormir etc. mas se alguém tiver outras atividades curriculares como nadar, jogar etc., essas podem ser expressas pela Interface.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.