Classe abstraite vs interface en Java


87

On m'a posé une question, je voulais que ma réponse soit examinée ici.

Q: Dans quel scénario est-il plus approprié d'étendre une classe abstraite plutôt que d'implémenter la ou les interfaces?

R: Si nous utilisons un modèle de conception de méthode de modèle.

Ai-je raison ?

Je regrette de ne pas avoir pu énoncer clairement la question.
Je connais la différence fondamentale entre la classe abstraite et l'interface.

1) utiliser une classe abstraite lorsque l'exigence est telle que nous devons implémenter la même fonctionnalité dans chaque sous-classe pour une opération spécifique (implémenter la méthode) et une fonctionnalité différente pour certaines autres opérations (uniquement les signatures de méthode)

2) utilisez l'interface si vous devez mettre la signature de manière identique (et l'implémentation différente) afin de pouvoir vous conformer à l'implémentation de l'interface

3) nous pouvons étendre au maximum une classe abstraite, mais nous pouvons implémenter plus d'une interface

Réitérant la question: y a-t-il d'autres scénarios, en plus de ceux mentionnés ci-dessus, où nous avons spécifiquement besoin d'utiliser une classe abstraite (on voit que le modèle de conception de méthode de modèle est conceptuellement basé uniquement sur cela)?

Interface vs classe abstraite

Le choix entre ces deux dépend vraiment de ce que vous voulez faire, mais heureusement pour nous, Erich Gamma peut nous aider un peu.

Comme toujours, il y a un compromis, une interface vous donne la liberté par rapport à la classe de base, une classe abstraite vous donne la liberté d'ajouter de nouvelles méthodes plus tard . - Erich Gamma

Vous ne pouvez pas changer une interface sans avoir à changer beaucoup d'autres choses dans votre code, donc le seul moyen d'éviter cela serait de créer une toute nouvelle interface, ce qui n'est peut-être pas toujours une bonne chose.

Abstract classesdoit principalement être utilisé pour des objets étroitement liés. Interfacessont plus efficaces pour fournir des fonctionnalités communes aux classes non liées.




Ce n'est pas un double. OP veut savoir quand étendre une classe abstraite plutôt que d'implémenter une interface. Il ne veut pas savoir quand écrire une classe abstraite ou une interface. Sa classe abstraite et son interface sont déjà écrites. Hd veut savoir s'il faut étendre ou implémenter.
Shiplu Mokaddim

1
@ shiplu.mokadd.im C'est une distinction sans différence. Vous ne pouvez pas utiliser une classe abstraite sans l'étendre. Votre pinaillage ici semble totalement inutile.
Marquis of Lorne

Réponses:


86

Quand utiliser les interfaces

Une interface permet à quelqu'un de partir de zéro pour implémenter votre interface ou implémenter votre interface dans un autre code dont le but initial ou principal était assez différent de votre interface. Pour eux, votre interface n'est qu'accessoire, quelque chose qui doit s'ajouter à leur code pour pouvoir utiliser votre package. L'inconvénient est que chaque méthode de l'interface doit être publique. Vous pourriez ne pas vouloir tout exposer.

Quand utiliser des classes abstraites

Une classe abstraite, en revanche, fournit plus de structure. Il définit généralement certaines implémentations par défaut et fournit des outils utiles pour une implémentation complète. Le hic, c'est que le code qui l'utilise doit utiliser votre classe comme base. Cela peut être très gênant si les autres programmeurs souhaitant utiliser votre package ont déjà développé leur propre hiérarchie de classes indépendamment. En Java, une classe ne peut hériter que d'une seule classe de base.

Quand utiliser les deux

Vous pouvez offrir le meilleur des deux mondes, une interface et une classe abstraite. Les implémenteurs peuvent ignorer votre classe abstraite s'ils le souhaitent. Le seul inconvénient de faire cela est d'appeler des méthodes via leur nom d'interface est légèrement plus lent que de les appeler via leur nom de classe abstrait.


Je pense que OP veut savoir quand étendre la classe abstraite plutôt que d'implémenter une interface
Shiplu Mokaddim

@ shiplu.mokadd.im En fait, le PO a posé une question très spécifique, à laquelle la réponse est «oui» ou «non».
Marquis of Lorne

4
Tu as raison. Mais dans SO, nous répondons oui / non avec une explication appropriée.
Shiplu Mokaddim le

1
@ shiplu.mokadd.im Je ne vois pas en quoi cela vous permet de mal formuler sa question.
Marquis of Lorne

Uniquement sur la base de cette seule déclaration If we are using template method design patternNous ne pouvons pas dire YESouNO
DivineDesert

31

réitérant la question: il y a tout autre scénario en plus de ceux mentionnés ci-dessus où nous avons spécifiquement besoin d'utiliser une classe abstraite (on voit que le modèle de conception de méthode de modèle est conceptuellement basé uniquement sur cela)

Oui, si vous utilisez JAXB. Il n'aime pas les interfaces. Vous devez soit utiliser des classes abstraites, soit contourner cette limitation avec des génériques.

À partir d' un blog personnel après :

Interface:

  1. Une classe peut implémenter plusieurs interfaces
  2. Une interface ne peut pas fournir de code du tout
  3. Une interface ne peut définir que des constantes finales statiques publiques
  4. Une interface ne peut pas définir de variables d'instance
  5. L'ajout d'une nouvelle méthode a des effets d'entraînement sur l'implémentation des classes (maintenance de la conception)
  6. JAXB ne peut pas gérer les interfaces
  7. Une interface ne peut pas étendre ou implémenter une classe abstraite
  8. Toutes les méthodes d'interface sont publiques

En général, les interfaces doivent être utilisées pour définir les contrats (ce qui doit être réalisé, pas comment y parvenir).

Classe abstraite:

  1. Une classe peut étendre au plus une classe abstraite
  2. Une classe abstraite peut contenir du code
  3. Une classe abstraite peut définir à la fois des constantes statiques et d'instance (final)
  4. Une classe abstraite peut définir des variables d'instance
  5. La modification du code de classe abstraite existant a des effets d'entraînement sur l'extension des classes (maintenance de l'implémentation)
  6. L'ajout d'une nouvelle méthode à une classe abstraite n'a aucun effet d'entraînement sur l'extension des classes
  7. Une classe abstraite peut implémenter une interface
  8. Les classes abstraites peuvent implémenter des méthodes privées et protégées

Les classes abstraites doivent être utilisées pour une implémentation (partielle). Ils peuvent être un moyen de restreindre la manière dont les contrats API doivent être mis en œuvre.


3
Dans Java 8 pour l'interface n ° 8, vous pouvez également avoir des méthodes defaultet static.
Utilisateur novice

15

L'interface est utilisée lorsque vous avez un scénario selon lequel toutes les classes ont la même structure mais ont totalement des fonctionnalités différentes.

La classe abstraite est utilisée lorsque vous avez un scénario selon lequel toutes les classes ont la même structure mais certaines fonctionnalités identiques et différentes.

Jetez un œil à l'article: http://shoaibmk.blogspot.com/2011/09/abstract-class-is-class-which-cannot-be.html


9

Il y a beaucoup de bonnes réponses ici, mais je trouve souvent que l'utilisation des DEUX interfaces et des classes abstraites est la meilleure voie. Considérez cet exemple artificiel:

Vous êtes développeur de logiciels dans une banque d'investissement et devez créer un système qui place des ordres sur un marché. Interface capture de ce qu'est un système commercial plus idée générale fait ,

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

et peut être capturé dans une interface, ITradeSystem

public interface ITradeSystem{

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

}

Désormais, les ingénieurs travaillant au bureau des ventes et dans d'autres secteurs d'activité peuvent commencer à s'interfacer avec votre système pour ajouter des fonctionnalités de placement de commande à leurs applications existantes. Et vous n'avez même pas encore commencé à construire! C'est la puissance des interfaces.

Alors vous allez de l'avant et construisez le système pour les négociants en actions ; ils ont entendu dire que votre système a une fonction pour trouver des actions bon marché et sont très impatients de l'essayer! Vous capturez ce comportement dans une méthode appelée findGoodDeals(), mais vous réalisez également qu'il y a beaucoup de choses compliquées qui sont impliquées dans la connexion aux marchés. Par exemple, vous devez ouvrir un 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);
    }

Les implémentations concrètes vont avoir beaucoup de ces méthodes désordonnées connectToMarket(), mais findGoodDeals()c'est tout ce dont les traders se soucient réellement.

Voici maintenant où les classes abstraites entrent en jeu. Votre patron vous informe que les traders de devises souhaitent également utiliser votre système. Et en regardant les marchés des devises, vous voyez que la plomberie est presque identique aux marchés boursiers. En fait, connectToMarket()peut être réutilisé textuellement pour se connecter aux marchés des changes. Cependant, findGoodDeals()c'est un concept très différent dans l'arène monétaire. Donc, avant de transmettre la base de code à l'enfant sorcier des changes de l'autre côté de l'océan, vous commencez par refactoriser en une abstractclasse, laissant non findGoodDeals()implémenté

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>
    }

Votre système boursier met findGoodDeals()en œuvre comme vous l'avez déjà défini,

public class StockTradeSystem extends ABCTradeSystem{    

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

mais maintenant, la gamine fétiche FX peut construire son système en fournissant simplement une implémentation de findGoodDeals()pour les devises; elle n'a pas à réimplémenter les connexions socket ou même les méthodes d'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);
    }

La programmation sur une interface est puissante, mais des applications similaires réimplémentent souvent des méthodes de manière presque identique. L'utilisation d'une classe abstraite évite les réimplémentations, tout en préservant la puissance de l'interface.

Remarque: on peut se demander pourquoi findGreatDeals()ne fait pas partie de l'interface. N'oubliez pas que l'interface définit les composants les plus généraux d'un système commercial. Un autre ingénieur peut développer un système commercial COMPLÈTEMENT DIFFÉRENT, où il ne se soucie pas de trouver de bonnes affaires. L'interface garantit que le bureau de vente peut également s'interfacer avec son système, il est donc préférable de ne pas enchevêtrer votre interface avec des concepts d'application tels que «bonnes affaires».


6

Lesquelles devez-vous utiliser, classes abstraites ou interfaces?

Envisagez d'utiliser des classes abstraites si l'une de ces instructions s'applique à votre cas d'utilisation:

Vous souhaitez partager du code entre plusieurs classes étroitement liées.

Vous vous attendez à ce que les classes qui étendent votre classe abstraite aient de nombreuses méthodes ou champs communs, ou nécessitent des modificateurs d'accès autres que publics (tels que protected et private).

Vous souhaitez déclarer des champs non statiques ou non finaux. Cela vous permet de définir des méthodes qui peuvent accéder et modifier l'état de l'objet auquel elles appartiennent.

Envisagez d'utiliser des interfaces si l'une de ces instructions s'applique à votre cas d'utilisation:

Vous vous attendez à ce que des classes non liées implémentent votre interface. Par exemple, les interfaces Comparable et Cloneable sont implémentées par de nombreuses classes indépendantes.

Vous souhaitez spécifier le comportement d'un type de données particulier, sans vous soucier de qui implémente son comportement.

Vous souhaitez profiter de l'héritage multiple de type.

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


4

Les choses ont beaucoup changé au cours des trois dernières années avec l'ajout de nouvelles fonctionnalités d'interface avec la version Java 8.

À partir de la page de documentation d'Oracle sur l'interface:

Une interface est un type de référence, similaire à une classe, qui ne peut contenir que des constantes, des signatures de méthode, des méthodes par défaut, des méthodes statiques et des types imbriqués. Les corps de méthode existent uniquement pour les méthodes par défaut et les méthodes statiques.

Comme vous l'avez mentionné dans votre question, la classe abstraite est la mieux adaptée pour le modèle de méthode modèle où vous devez créer un squelette. L'interface ne peut pas être utilisée ici.

Une autre considération pour préférer la classe abstraite à l'interface:

Vous n'avez pas d'implémentation dans la classe de base et seules les sous-classes doivent définir leur propre implémentation. Vous avez besoin d'une classe abstraite au lieu d'une interface car vous souhaitez partager l'état avec des sous-classes.

La classe abstraite établit "est une" relation entre les classes liées et l'interface fournit "a une" capacité entre les classes non liées .


En ce qui concerne la deuxième partie de votre question, ce qui est valable pour la plupart des langages de programmation , y compris java avant java-8 version

Comme toujours, il y a un compromis, une interface vous donne la liberté par rapport à la classe de base, une classe abstraite vous donne la liberté d'ajouter de nouvelles méthodes plus tard. - Erich Gamma

Vous ne pouvez pas changer une interface sans avoir à changer beaucoup d'autres choses dans votre code

Si vous préférez que la classe abstraite s'interface plus tôt avec les deux considérations ci-dessus, vous devez repenser maintenant car les méthodes par défaut ont ajouté de puissantes capacités aux interfaces.

Les méthodes par défaut vous permettent d'ajouter de nouvelles fonctionnalités aux interfaces de vos bibliothèques et d'assurer la compatibilité binaire avec le code écrit pour les anciennes versions de ces interfaces.

Pour sélectionner l'un d'entre eux entre l'interface et la classe abstraite, la page de documentation d'Oracle cite que:

Les classes abstraites sont similaires aux interfaces. Vous ne pouvez pas les instancier et ils peuvent contenir un mélange de méthodes déclarées avec ou sans implémentation. Cependant, avec les classes abstraites, vous pouvez déclarer des champs qui ne sont pas statiques et définitifs et définir des méthodes concrètes publiques, protégées et privées.

Avec les interfaces, tous les champs sont automatiquement publics, statiques et définitifs, et toutes les méthodes que vous déclarez ou définissez (comme méthodes par défaut) sont publiques. De plus, vous ne pouvez étendre qu'une seule classe, qu'elle soit abstraite ou non, alors que vous pouvez implémenter n'importe quel nombre d'interfaces.

Reportez-vous à ces questions connexes pour plus de détails:

Interface vs classe abstraite (OO général)

Comment aurais-je dû expliquer la différence entre une interface et une classe abstraite?

En résumé: la balance penche désormais davantage vers les interfaces .

Existe-t-il d'autres scénarios, en plus de ceux mentionnés ci-dessus, où nous avons spécifiquement besoin d'utiliser une classe abstraite (on voit que le modèle de conception de méthode de modèle est conceptuellement basé uniquement sur cela)?

Certains modèles de conception utilisent des classes abstraites (sur des interfaces) en dehors du modèle de méthode Template.

Modèles de création:

Abstract_factory_pattern

Modèles structurels:

Decorator_pattern

Modèles de comportement:

Mediator_pattern


Ceci: "La classe abstraite établit" est une "relation entre les classes liées et l'interface fournit" a une "capacité entre des classes non liées".
Gabriel

3

Vous n'avez pas raison. Il existe de nombreux scénarios. Il n'est tout simplement pas possible de le réduire à une seule règle de 8 mots.


1
Sauf si vous êtes vague comme; Utilisez une interface chaque fois que vous le pouvez;)
Peter Lawrey

@PeterLawrey Ouais, ne laissez pas les disputes circulaires vous ralentir ;-)
Marquis of Lorne

C'est un "débordement de pile" après tout. ;) Mon point étant que si vous pouvez utiliser l'interface plus simple, faites-le. Sinon, vous n'avez pas d'autre choix que d'utiliser une classe abstraite. Je ne vois pas cela comme très compliqué.
Peter Lawrey

Je pense que vous pourriez fournir une idée plus constructive. comme parler de certains scénarios représentatifs /
Adams.H

3

La réponse la plus courte est: étendre la classe abstraite lorsque certaines des fonctionnalités que vous recherchez y sont déjà implémentées.

Si vous implémentez l'interface, vous devez implémenter toute la méthode. Mais pour la classe abstraite, le nombre de méthodes que vous devez implémenter peut être inférieur.

Dans le modèle de conception de modèle , un comportement doit être défini. Ce comportement dépend d'autres méthodes qui sont abstraites. En créant une sous-classe et en définissant ces méthodes, vous définissez en fait le comportement principal. Le comportement sous-jacent ne peut pas être dans une interface car l'interface ne définit rien, elle le déclare simplement. Ainsi, un modèle de conception de modèle est toujours accompagné d'une classe abstraite. Si vous souhaitez conserver le flux du comportement intact, vous devez étendre la classe abstraite mais ne remplacez pas le comportement principal.


Une référence supplémentaire pour Pure Virtual Function ajoutera plus d'informations sur la convergence de la classe abstraite et de l'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. partie (1/2)
Abhijeet

Partie (2/2) La divergence de la classe abstraite et de l'interface est expliquée par la dernière ligne ci-dessus no data members or ordinary methods[dans la classe abstraite].
Abhijeet

3

À mon avis, la différence fondamentale est que an interface can't contain non abstract methods while an abstract class can. Ainsi, si les sous-classes partagent un comportement commun, ce comportement peut être implémenté dans la super classe et donc hérité dans les sous-classes

J'ai également cité ce qui suit dans le livre "Software architecture design ppatterns in java"

"Dans le langage de programmation Java, il n'y a pas de support pour l'héritage multiple. Cela signifie qu'une classe ne peut hériter que d'une seule classe. Par conséquent, l'héritage ne doit être utilisé que lorsque cela est absolument nécessaire. Dans la mesure du possible, les méthodes dénotant le comportement commun doivent être déclarées dans sous la forme d'une interface Java à implémenter par différentes classes d'implémentation. Mais les interfaces souffrent de la limitation qu'elles ne peuvent pas fournir d'implémentations de méthode. Cela signifie que chaque implémenteur d'une interface doit implémenter explicitement toutes les méthodes déclarées dans une interface, même lorsque certaines de ces Les méthodes représentent la partie invariable de la fonctionnalité et ont exactement la même implémentation dans toutes les classes d'implémentation, ce qui conduit à un code redondant.L'exemple suivant montre comment le modèle de classe parent abstraite peut être utilisé dans de tels cas sans nécessiter d'implémentations de méthodes redondantes. "


2

Les classes abstraites sont différentes des interfaces sur deux aspects importants

  • ils fournissent une implémentation par défaut pour les méthodes choisies (qui est couverte par votre réponse)
  • les classes abstraites peuvent avoir un état (variables d'instance) - c'est donc une autre situation dans laquelle vous voulez les utiliser à la place des interfaces

Je voudrais compléter que les interfaces peuvent avoir des variables mais elles sont par défaut définitives.
Tomasz Mularczyk

1

C'est une bonne question. Les deux ne sont pas similaires mais peuvent être utilisées pour une partie de la même raison, comme une réécriture. Lors de la création, il est préférable d'utiliser Interface. Quand il s'agit de classe, c'est bon pour le débogage.


0

Abstract classes should be extended when you want to some common behavior to get extended. La super classe abstraite aura le comportement commun et définira une méthode abstraite / un comportement spécifique que les sous-classes devraient implémenter.

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


0

C'est ma compréhension, j'espère que cela aide

Classes abstraites:

  1. Peut avoir des variables membres héritées (impossible à faire dans les interfaces)
  2. Peut avoir des constructeurs (les interfaces ne peuvent pas)
  3. Ses méthodes peuvent avoir n'importe quelle visibilité (ie: privée, protégée, etc. - alors que toutes les méthodes d'interface sont publiques)
  4. Peut avoir des méthodes définies (méthodes avec une implémentation)

Interfaces:

  1. Peut avoir des variables, mais ce sont toutes des variables finales statiques publiques
    • valeurs constantes qui ne changent jamais avec une portée statique
    • les variables non statiques nécessitent une instance et vous ne pouvez pas instancier une interface
  2. Toutes les méthodes sont abstraites (pas de code dans les méthodes abstraites)
    • tout le code doit être réellement écrit dans la classe qui implémente l'interface particulière

0

Utilisation du résumé et de l'interface:

L'un a "Is-A-Relationship" et un autre a "Has-A-Relationship"

Les propriétés par défaut ont été définies dans abstrait et des propriétés supplémentaires peuvent être exprimées via l'interface.

Exemple: -> Chez les êtres humains, nous avons des propriétés par défaut qui mangent, dorment, etc.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.