Pourquoi devrais-je déclarer une classe en tant que classe abstraite?


40

Je connais la syntaxe, les règles appliquées à la classe abstraite et je veux savoir utiliser une classe abstraite

La classe abstraite ne peut pas être instanciée directement mais peut être étendue par une autre classe

Quel est l'avantage de le faire?

Comment est-ce différent d'une interface?

Je sais qu'une classe peut implémenter plusieurs interfaces mais ne peut étendre qu'une classe abstraite. Est-ce seulement une différence entre une interface et une classe abstraite?

Je suis conscient de l'utilisation d'une interface. J'ai appris cela du modèle de délégation d'événements d'AWT en Java.

Dans quelles situations dois-je déclarer la classe comme une classe abstraite? Quels sont les avantages de cela?


14
Cela a été demandé, vous savez. Une recherche posera d'autres questions comme celle-ci. Vous devriez commencer sur Google, ce qui vous mènera à Stack Overflow. Tous ces éléments sont des doublons: stackoverflow.com/search?q=abstract+interface .
S.Lott

1
"utilisation de la classe abstraite dont ils discutent juste ... des règles". Quelle? Quelle est la différence entre "règles" et "utilisation"? Votre question exacte a été posée, en passant. Je sais. J'ai répondu Continuer de regarder. Il est important d'apprendre à utiliser la recherche.
S.Lott

Je veux dire "Dans quelles situations dois-je déclarer une classe en tant que classe abstraite? Quels sont les avantages de cela?"
Vaibhav Jani

Une interface est une classe abstraite pure, c'est tout. Ils sont l'un dans le même. J'utilise tout le temps une classe abstraite pour une fonction de la classe de base qui ne peut pas être implémentée car elle a besoin de données que seules les sous-classes possèdent, mais je veux m'assurer que chaque sous-classe possède cette fonction et l'implémente en conséquence.
AngryBird

Je trouve que le modèle de méthode template est très puissant et constitue un bon cas d’utilisation pour les classes abstraites.
m3th0dman

Réponses:


49

Cette réponse explique très bien les différences entre une classe abstraite et une interface, mais ne dit pas pourquoi vous devriez en déclarer une.

D'un point de vue purement technique, il n'est jamais nécessaire de déclarer une classe abstraite.

Considérez les trois classes suivantes:

class Database { 
    public String[] getTableNames() { return null; } //or throw an exception? who knows...
}

class SqlDatabase extends Database { } //TODO: override getTableNames

class OracleDatabase extends Database { }  //TODO: override getTableNames

Vous n'avez pas besoin de rendre la classe Database abstraite, même si son implémentation pose un problème évident: lorsque vous écrivez ce programme, vous pouvez taper new Database()et il serait valide, mais cela ne fonctionnerait jamais.

Quoi qu'il en soit, vous obtiendriez toujours un polymorphisme. Ainsi, tant que votre programme ne fabrique SqlDatabaseque des OracleDatabaseinstances, vous pouvez écrire des méthodes telles que:

public void printTableNames(Database database) {
    String[] names = database.getTableNames();
}

Les classes abstraites améliorent la situation en empêchant un développeur d'instancier la classe de base, car un développeur l'a marquée avec une fonctionnalité manquante . Il offre également une sécurité au moment de la compilation, vous permettant ainsi de vous assurer que toutes les classes qui étendent votre classe abstraite fournissent la fonctionnalité minimale nécessaire pour fonctionner, sans avoir à vous soucier de la possibilité d'utiliser des méthodes de stub (comme celle ci-dessus) que les héritiers ont en quelque sorte. comme par magie, ils doivent redéfinir une méthode pour la faire fonctionner.

Les interfaces sont un sujet totalement séparé. Une interface vous permet de décrire les opérations pouvant être effectuées sur un objet. Vous utiliserez généralement des interfaces lors de l'écriture de méthodes, de composants, etc., qui utilisent les services d'autres composants, d'objets, mais vous ne vous souciez pas du type d'objet à partir duquel vous obtenez les services.

Considérez la méthode suivante:

public void saveToDatabase(IProductDatabase database) {
     database.addProduct(this.getName(), this.getPrice());
}

Vous ne vous souciez pas de savoir si l' databaseobjet hérite d'un objet particulier, vous vous souciez juste qu'il ait une addProductméthode. Ainsi, dans ce cas, une interface convient mieux que de faire en sorte que toutes vos classes héritent de la même classe de base.

Parfois, la combinaison des deux fonctionne très bien. Par exemple:

abstract class RemoteDatabase implements IProductDatabase { 
    public abstract String[] connect();
    public abstract void writeRow(string col1, string col2);

    public void addProduct(String name, Double price) {
        connect();
        writeRow(name, price.toString());
    }
}

class SqlDatabase extends RemoteDatabase {
    //TODO override connect and writeRow
}

class OracleDatabase extends RemoteDatabase { 
    //TODO override connect and writeRow
}

class FileDatabase implements IProductDatabase {
    public void addProduct(String name, Double price) {
         //TODO: just write to file
    }
}

Notez que certaines des bases de données héritent de RemoteDatabase pour partager certaines fonctionnalités (comme se connecter avant d'écrire une ligne), mais FileDatabase est une classe distincte à implémenter uniquement IProductDatabase.


16

Similitudes

Les classes abstraites et les interfaces sont nécessaires pour l'abstraction. Ils ne peuvent pas être instanciés avec un nouveau , mais peuvent être résolus en inversant des conteneurs de contrôle ou via des modèles d'usine.

Différence

  1. Des interfaces

    • Définir un contrat public bien connu, des capacités du type
    • Applicable pour afficher l'héritage horizontal, c'est-à-dire la création de branches sur le premier niveau d'héritage (par exemple, ILog pour définir les fonctions de journalisation dans une base de données, un fichier texte, XML, SOAP, etc.)
    • Tous les membres sont publics
    • Aucune implémentation autorisée
    • L'héritage enfant peut avoir de nombreuses interfaces à implémenter
    • Utile pour l'intégration de tiers
    • Nommer commence habituellement par I
  2. Classe abstraite

    • Définir la structure, l'identité et certains comportements pris en charge par défaut
    • Applicable pour montrer l'héritage vertical, c'est-à-dire les ramifications profondes sur plusieurs niveaux (par exemple, la classe AbstractEntity dans le développement dirigé par domaine)
    • Les membres peuvent avoir une visibilité différente (du public au privé)
    • Vous pouvez implémenter certains membres (par exemple * classes de lecteurs)
    • Héritage enfant ne peut avoir qu'une seule classe abstraite de base

Il est en fait facile de trouver la réponse par simple requête google .


qu'est-ce que vous mena par mise en œuvre non autorisé? La classe Java peut implémenter des interfaces.
Sajuuk

@Sajuuk cette ligne se réfère à une interface. Vous ne pouvez pas mettre en œuvre un contrat dans une interface. Vous pouvez avoir une implémentation par défaut d'un contrat dans une classe abstraite.
oleksii

11

Comment est-ce différent d'une interface?

Dans une classe abstraite, vous pouvez implémenter certaines méthodes et laisser (forcer) le reste à mettre en œuvre par la classe étendue. Vous ne pouvez pas implémenter de méthodes dans une interface. Vous ne pouvez forcer personne à ignorer quoi que ce soit lors de l'extension d'une classe ordinaire. Avec une classe abstraite, vous pouvez.


Cela nécessite vraiment une mise à jour pour Java 8, où les méthodes par défaut ont été introduites.
Haakon Løtveit

8

Les classes abstraites sont pour "est un" et les interfaces sont pour "peut faire".

Les classes abstraites vous permettent d'ajouter un comportement de base afin que les programmeurs n'aient pas à tout coder, tout en les forçant à suivre votre conception.


3

Outre les détails techniques profonds - comme la mise en œuvre de certaines méthodes pour les classes abstraites, etc., le sens est le suivant:

Les interfaces définissent une capacité commune - IEnumerable définit que la classe qui implémente cette interface peut être énumérée. Cela ne dit rien sur la classe elle-même.

Les classes abstraites (ou de base) définissent le comportement - WebRequest définit un comportement commun à toutes les classes enfants telles que HttpWebRequest, etc. Il définit la signification principale de la classe et son objectif réel: accéder aux ressources Web.


2

Entrée Wikipedia .

La principale différence entre une interface et une classe abstraite réside dans le fait qu’une classe abstraite peut fournir des méthodes implémentées. Avec les interfaces, vous ne pouvez déclarer que des méthodes, écrire leur signature. Voici un exemple de classe qui étend une classe abstraite qui implémente deux interfaces: (java)

interface MyInterface1 {
  string getValue1();
}

interface MyInterface2 {
  string getValue2();
}

abstract class MyAbstractClass implements MyInterface1, MyInterface2{
  void printValues() {
    System.out.println("Value 1: " + getValue1() + ", Value 2: " + getValue2() + 
                       ", Value 3: " + getValue3());
  }

  protected abstract string getValue3();
}

class ImpClass extends MyAbstractClass {
  public string getValue1() {
    return "1";
  }

  public string getValue2() {
    return "2";
  }

  protected string getValue3() {
    return "3";
  }
}

Dans cet exemple, MyAbstractClass fournit une méthode publique qui affiche les trois valeurs. Dans ImpClass, vous devez implémenter getValue1 et getValue2 respectivement à partir de MyInterface1 et MyInterface2 et getValue3 à partir de la classe abstraite.

Voilà.

Il y a plus d'aspects (interface: uniquement les méthodes publiques, classe abstraite: méthodes abstraites protégées et abstraites publiques), mais vous pouvez le lire vous-même.

Sur une note finale, une classe abstraite qui fournit uniquement des méthodes abstraites est une classe de base abstraite "pure", également appelée interface.


2
  • Interface - lorsque quelques classes partagent une API (noms de méthodes et paramètres)
  • Classe abstraite - lorsque quelques classes partagent le même code (implémentation)

En d'autres termes, vous devriez commencer par une question: "ces classes partagent-elles nécessairement l' implémentation ou ont-elles simplement une interface commune ?"

Si la réponse est mixte, telle que - ces trois classes doivent partager l'implémentation, mais que ces deux autres ne partagent que leur API - vous pouvez alors créer une interface pour les cinq et une classe abstraite pour ces trois avec le commun code.

Il existe également d'autres méthodes pour partager l'implémentation, par exemple pour encapsuler un objet avec cette implémentation (par exemple, dans le modèle Stratégie ).


1

Vous déclareriez un résumé de classe lorsque vous ne souhaitez pas que le développeur (probablement vous-même) soit autorisé à l'instancier, car cela ne fonctionnerait pas ou n'aurait pas de sens.

Par exemple, considérons un jeu dans lequel il existe différents types d’entités de jeu. Ils héritent tous de la baseGameEntity classe de .

abstract class GameEntity{

    int lifePoint, speed, damage;

    public attack(GameEntity target){ target.damage(damage); }

    public damage(int damageInflicted){ lifePoint -= damageInflicted - speed; }

    // etc...

}

Cette classe est déclarée abstract car cela n'aurait aucun sens de l'instancier. Il déclare certaines actions pour les entités de jeu et certains attributs, mais ces attributs ne sont nulle part dans cette classe initialisés. Cette classe sert de modèle aux entités du jeu, mais n'est pas censée être instanciée par elle-même, et en tant que telle déclarée abstract.

En ce qui concerne la différence d'utilisation entre une classe abstraite et une interface:

Selon moi, une interface est un moyen d'obtenir un comportement polymorphe sans être limitée par le mécanisme d'héritage unique de certaines langues.

Revenons au jeu à titre d'exemple. Considérons une classe Enemydérivée deGameEntity . Cette classe a une méthode attackMeFromDistance(RangedAttacker attacker). Cette méthode est destinée à permettre aux entités d’attaquer l’ennemi de très loin.

Comme vous pouvez le constater, cette méthode prend un RangedAttackertype en tant que paramètre. Cependant, toutes les entités de jeu héritent déjà deGameEntity . Ils ne peuvent pas prolonger une autre classe.

Prenez les cours Mageet Archerpar exemple. Nous voulons permettre que les deux soient acceptés comme paramètres de la attackMeFromDistance(RangedAttacker attacker)méthode, mais ils sont déjà dérivés deGameEntity .

Pour résoudre ce problème, nous créons une nouvelle interface:

interface RangedAttacker{
    public void attackFromDistance();
}

Une classe qui implémente cette interface doit implémenter la attackFromDistance()méthode et il est donc assuré qu'elle dispose de capacités d'attaque à distance. Cela signifie que la attackMeFromDistanceméthode peut maintenant accepter en toute sécurité les classes qui implémentent cette interface. Donc faire MageetArcher mettre en œuvre cette interface résout notre problème.

Pour moi, c'est le pouvoir des interfaces.

Donc, pour résumer, vous utiliseriez habituellement une classe abstraite lorsque vous voulez avoir une classe de base pour certaines classes, mais cela n'aurait pas de sens de l'instancier par lui-même (ou dans le cas où il a des abstractméthodes, qui doivent être implémenté par les sous-classes, et dans ce cas le compilateur vous obligerait à faire la classe abstract). Vous utiliseriez une interface pour obtenir un comportement polymorphe sans être limité par le mécanisme d'héritage unique.


0
  1. Il est possible que trop peu de méthodes soient communes à une classe (logique métier). Et les méthodes restantes sont différentes. Dans ce type de scénario, vous pouvez implémenter toutes les méthodes courantes dans une classe et déclarer le reste abstrait. Ensuite, vous devez déclarer la classe abstraite.
  2. Parfois, vous n'autorisez pas la création d'objet directement dans la classe. Ce genre de classe dont vous avez besoin pour déclarer la classe abstraite.
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.