Interface ou classe abstraite: laquelle utiliser?

327

Veuillez expliquer quand utiliser un PHP interfaceet quand utiliser un abstract class?

Comment puis-je changer mon entrée abstract classen un interface?

Darryl Hein
la source

Réponses:

458

Utilisez une interface lorsque vous souhaitez forcer les développeurs travaillant dans votre système (vous-même inclus) à implémenter un certain nombre de méthodes sur les classes qu'ils vont construire.

Utilisez une classe abstraite lorsque vous souhaitez forcer les développeurs travaillant dans votre système (vous-même inclus) à implémenter un nombre défini de méthodes et que vous souhaitez fournir des méthodes de base qui les aideront à développer leurs classes enfants.

Une autre chose à garder à l'esprit est que les classes clientes ne peuvent étendre qu'une seule classe abstraite, alors qu'elles peuvent implémenter plusieurs interfaces. Donc, si vous définissez vos contrats de comportement dans des classes abstraites, cela signifie que chaque classe enfant ne peut se conformer qu'à un seul contrat. Parfois, c'est une bonne chose, lorsque vous souhaitez forcer vos utilisateurs-programmeurs le long d'un chemin particulier. D'autres fois, ce serait mauvais. Imaginez si les interfaces Countable et Iterator de PHP étaient des classes abstraites au lieu d'interfaces.

Une approche courante lorsque vous n'êtes pas sûr de la voie à suivre (comme mentionné par cletus ci-dessous ) consiste à créer une interface, puis à ce que votre classe abstraite implémente cette interface.

Alan Storm
la source
12
J'essayais toute la journée de comprendre les usages abstractet les interfacecours, votre message a été clair. Merci beaucoup Alan
afarazit
4
Un autre avantage des classes abstraites est la possibilité de définir des méthodes protégées abstraites . Pas toujours utile, mais peut être utile dans certaines architectures.
netcoder
Donc, dans de nombreux cas, nous devrions utiliser la classe abstraite en raison de la flexibilité - c'est ma conclusion :)
ymakux
3
@volocuga: pas nécessairement, comme l'a souligné Alan, un seul résumé peut être étendu. Personnellement, je n'aime pas que le résumé implémente une idée d'interface car il contribue à l'obscurcissement du code et est moins direct, IMO.
Préfixe
171

Les différences entre un Abstract Classet un Interface:

Classes abstraites

Une classe abstraite peut fournir certaines fonctionnalités et laisser le reste à la classe dérivée .

  • La classe dérivée peut ou non remplacer les fonctions concrètes définies dans la classe de base.

  • Une classe enfant étendue à partir d'une classe abstraite doit logiquement être liée.

Interface

Une interface ne peut contenir aucune fonctionnalité . Il ne contient que des définitions des méthodes.

  • La classe dérivée DOIT fournir du code pour toutes les méthodes définies dans l'interface .

  • Des classes complètement différentes et non liées peuvent être regroupées logiquement à l'aide d'une interface.

kn3l
la source
1
Pouvez-vous fournir un exemple concret pour le démontrer?
RN Kushwaha
1
Quelle est la différence entre abstract class X implements Yet class X implements Y?
Webinan
3
@Webinan In abstract class X implements Yvous déclarez que la fonctionnalité en bloc de X doit être implémentée dans une classe dérivée et que la classe abstraite et dérivée doivent contenir des fonctions définies dans Y, alors class X implements Yque cela implique seulement que la classe X doit contenir des fonctions définies dans Y. Si votre interface Y n'est pas destiné à être implémenté par une autre classe que XI ignorerait en fait la définition de Y en tant qu'interface et implémenterait uniquement les fonctions dans Y en tant que fonction abstraite publique / protégée / privée pour s'assurer qu'elles sont implémentées dans la classe dérivée.
Calle Bergström
1
Les interfaces peuvent non seulement contenir la définition de méthodes, elles peuvent également contenir des constantes
Thielicious
J'ai aimé votre comparaison. Je voulais donc ajouter quelque chose. Les interfaces peuvent avoir des constantes de classe hors de la boîte tandis que la classe abstraite ne peut pas.
Noman Ibrahim
128

Pourquoi utiliser des classes abstraites? Voici un exemple simple. Disons que nous avons le code suivant:

<?php 

class Fruit {
    private $color;

    public function eat() {
        // chew
    }

    public function setColor($c) {
        $this->color = $c;
    }
}

class Apple extends Fruit {
    public function eat() {
        // chew until core
    }
}

class Orange extends Fruit {
    public function eat() {
        // peeling
        // chew
    }
}

Maintenant, je vous donne une pomme et vous la mangez. Ca a quel goût? Ça a le goût d'une pomme.

<?php 
$apple = new Apple();
$apple->eat();

// Now I give you a fruit.
$fruit = new Fruit();
$fruit->eat();

Quel goût ça a? Eh bien, cela n'a pas beaucoup de sens, vous ne devriez donc pas être en mesure de le faire. Ceci est accompli en faisant l'abstrait de la classe Fruit ainsi que la méthode eat à l'intérieur.

<?php 
abstract class Fruit {
    private $color;

    abstract public function eat(){}

    public function setColor($c) {
        $this->color = $c;
    }
}
?>

Une classe abstraite est comme une interface, mais vous pouvez définir des méthodes dans une classe abstraite alors que dans une interface, elles sont toutes abstraites. Les classes abstraites peuvent avoir à la fois des méthodes vides et des méthodes de travail / concrètes. Dans les interfaces, les fonctions qui y sont définies ne peuvent pas avoir de corps. Dans les classes abstraites, ils le peuvent.

Un exemple du monde réel:

<?php 
abstract class person {

    public $LastName;
    public $FirstName;
    public $BirthDate;

    abstract protected function write_info();
}

final class employee extends person{

    public $EmployeeNumber;
    public $DateHired;

    public function write_info(){
        //sql codes here
        echo "Writing ". $this->LastName . "'s info to emloyee dbase table <br>";   
    }
}

final class student extends person{

    public $StudentNumber;
    public $CourseName;

    public function write_info(){
        //sql codes here
        echo "Writing ". $this->LastName . "'s info to student dbase table <br>";
    }
}

///----------
$personA = new employee;
$personB = new student;

$personA->FirstName="Joe";
$personA->LastName="Sbody";

$personB->FirstName="Ben";
$personB->LastName="Dover";

$personA->write_info();
// Writing Sbody's info to emloyee dbase table
$personB->write_info();
// Writing Dover's info to student dbase table 
Vineesh Kalarickal
la source
2
Bonjour, cette réponse a probablement obtenu des votes négatifs en raison de la façon dont elle est formatée. Ce serait bien si ce n'était pas un gros bloc de code (quatre espaces font quelque chose dans un bloc de code, désindenter le texte pour le retirer du bloc), et si cela a été copié-collé quelque part (il ressemble à ça) il serait poli de les créditer.
Camilo Martin
9
Je t'aime pour l'homme exemple de fruits! Depuis que j'ai commencé à apprendre le php, cet exemple me montre clairement merci
Raheel
23
+1 What does that taste like? Well, it doesn't make much sense, so you shouldn't be able to do that.Maintenant, je connais l'abstrait!
Webinan
Que fait le finalmot-clé? Excellent article, merci.
Gus
1
@VineeshKalarickal Ce que je ne comprends pas dans l'exemple Person, c'est la différence entre: 1) l'utilisation de la classe abstraite Person (comme dans l'exemple); 2) écrire Person en tant que classe standard et obliger Employee et Student à remplacer la méthode write_info ().
Ferex
66

La meilleure pratique consiste à utiliser une interface pour spécifier le contrat et une classe abstraite comme une seule implémentation de celui-ci. Cette classe abstraite peut remplir une grande partie du passe-partout afin que vous puissiez créer une implémentation en remplaçant simplement ce dont vous avez besoin ou ce que vous voulez sans vous forcer à utiliser une implémentation particulière.

cletus
la source
37

Juste pour jeter cela dans le mélange, mais comme Cletus l'a mentionné en utilisant une interface en conjonction avec une classe abstraite, j'utilise souvent l'interface pour clarifier ma pensée de conception.

Par exemple:

<?php
class parser implements parserDecoratorPattern {
    //...
}

De cette façon, toute personne lisant mon code (et qui sait ce qu'est un modèle de décorateur) saura immédiatement a) comment je construis mon analyseur et b) pourra voir quelles méthodes sont utilisées pour implémenter le modèle de décorateur.

De plus, et je peux être hors de la base ici, n'étant pas un programmeur Java / C ++ / etc, mais les types de données peuvent entrer en jeu ici. Vos objets sont d'un type, et lorsque vous les transmettez, le type importe par programme. Le déplacement de vos éléments contractables dans l'interface ne dicte que les types renvoyés par les méthodes, mais pas le type de base de la classe qui l'implémente.

Il est tard et je ne peux pas penser à un meilleur exemple de psudo-code, mais voici:

<?php
interface TelevisionControls {};
class Remote implements TelevisionControls {};
class Spouse implements TelevisionControls {};
Spouse spouse = new Spouse();
Remote remote = new Remote();
isSameType = (bool)(remote == spouse)
Austen Hoogen
la source
1
Quel bel exemple! ;)
Joel Murphy
@ matt2000 Pas sexiste ET fonctionne aussi pour les mariages homosexuels. Bon montage. :)
Austen Hoogen
4
Ceci est un exemple génial! Cependant, je ne pense pas que vous puissiez instancier une classe abstraite mais plutôt une classe qui s'étend d'une classe abstraite
Arielle Nguyen
2
ne tuerait pas pour que le sudo-code ressemble au moins au langage en question. quelqu'un devrait y mettre des $.
J'ai lutté un ours une fois.
2
Bien que l'exemple soit drôle, nous ne pouvons pas instancier directement une classe abstraite, veuillez apporter des modifications dans l'exemple afin que les gens ne la considèrent pas comme une utilisation valide en PHP.
saji89
16

La principale différence est qu'une classe abstraite peut contenir une implémentation par défaut, contrairement à une interface.

Une interface est un contrat de comportement sans aucune implémentation.

Blé Mitch
la source
16

J'aimerais également ajouter ici que le fait que tout autre langage OO possède une sorte d'interface et l'abstraction ne signifie pas non plus qu'ils ont la même signification et le même objectif qu'en PHP. L'utilisation d'abstraction / interfaces est légèrement différente tandis que les interfaces en PHP n'ont en fait pas de fonction réelle. Ils sont simplement utilisés pour des raisons sémantiques et liées au schéma. Le but est d'avoir un projet aussi flexible que possible, extensible et sûr pour les futures extensions, que le développeur ait ou non un plan d'utilisation totalement différent.

Si votre anglais n'est pas natif, vous pouvez rechercher ce que sont réellement l'abstraction et les interfaces. Et cherchez aussi des synonymes.

Et cela pourrait vous aider comme métaphore:

INTERFACE

Disons que vous faites une nouvelle sorte de gâteau avec des fraises et que vous avez préparé une recette décrivant les ingrédients et les étapes. Vous seul savez pourquoi il a si bon goût et vos invités l'aiment. Ensuite, vous décidez de publier votre recette afin que d'autres personnes puissent également essayer ce gâteau.

Le point ici est

- pour bien faire les choses
- pour être prudent
- pour éviter les choses qui pourraient aller mal (comme trop de fraises ou quelque chose)
- pour que les gens qui l'essayent restent faciles
- pour vous dire combien de temps est ce qu'il faut faire (comme le fait de cuire) )
- pour dire quelles choses vous POUVEZ faire mais que vous N'AVEZ PAS

C'est exactement cela qui décrit les interfaces. C'est un guide, un ensemble d'instructions qui respectent le contenu de la recette. Comme si vous vouliez créer un projet en PHP et que vous vouliez fournir le code sur GitHub ou avec vos amis ou autre chose. Une interface est ce que les gens peuvent faire et ce que vous ne devriez pas faire. Règles qui le tiennent - si vous désobéissez à un, la construction entière sera cassée.


ABSTRACTION

Pour continuer avec cette métaphore ici ... imaginez, vous êtes l'invité cette fois en train de manger ce gâteau. Ensuite, vous essayez ce gâteau en utilisant la recette maintenant. Mais vous voulez ajouter de nouveaux ingrédients ou changer / sauter les étapes décrites dans la recette. Alors qu'est-ce qui vient ensuite? Planifiez une version différente de ce gâteau. Cette fois avec des baies noires et non des baies de paille et plus de crème à la vanille ... délicieux.

C'est ce que vous pourriez considérer comme une extension du gâteau d'origine. Vous en faites une abstraction en créant une nouvelle recette parce que c'est un peu différent. Il a quelques nouvelles étapes et autres ingrédients. Cependant, la version aux baies noires contient certaines parties que vous avez reprises de l'original - ce sont les étapes de base que chaque type de gâteau doit avoir. Comme des ingrédients comme le lait - c'est ce que chaque classe dérivée a.

Maintenant, vous voulez échanger des ingrédients et des étapes et ceux-ci DOIVENT être définis dans la nouvelle version de ce gâteau. Ce sont des méthodes abstraites qui doivent être définies pour le nouveau gâteau, car il devrait y avoir un fruit dans le gâteau, mais lequel? Vous prenez donc les baies noires cette fois. Terminé.

Voilà, vous avez prolongé le gâteau, suivi l'interface et extrait les étapes et les ingrédients.

Thielicious
la source
1
Cela a été ma comparaison préférée de tout ce qui concerne PHP. C'était vraiment logique. Je vous remercie!
cbloss793
13

Pour ajouter à certaines des réponses déjà excellentes:

  • Les classes abstraites vous permettent de fournir un certain degré d'implémentation, les interfaces sont de purs modèles. Une interface ne peut que définir des fonctionnalités , elle ne peut jamais les implémenter.

  • Toute classe qui implémente l'interface s'engage à implémenter toutes les méthodes qu'elle définit ou elle doit être déclarée abstraite.

  • Les interfaces peuvent aider à gérer le fait que, comme Java, PHP ne prend pas en charge l'héritage multiple. Une classe PHP ne peut étendre qu'un seul parent. Cependant, vous pouvez faire une promesse de classe d'implémenter autant d'interfaces que vous le souhaitez.

  • type: pour chaque interface qu'elle implémente, la classe prend le type correspondant. Étant donné que toute classe peut implémenter une interface (ou plusieurs interfaces), les interfaces joignent efficacement les types qui ne sont autrement pas liés.

  • une classe peut à la fois étendre une superclasse et implémenter n'importe quel nombre d'interfaces:

    class SubClass extends ParentClass implements Interface1, Interface2 {
        // ...
    }

Veuillez expliquer quand utiliser une interface et quand utiliser une classe abstraite?

Utilisez une interface lorsque vous devez fournir uniquement un modèle sans implémentation, et vous voulez vous assurer que toute classe qui implémente cette interface aura les mêmes méthodes que toute autre classe qui l'implémente (au moins).

Utilisez une classe abstraite lorsque vous souhaitez créer une fondation pour d'autres objets (une classe partiellement construite). La classe qui étend votre classe abstraite utilisera certaines propriétés ou méthodes définies / implémentées:

<?php
// interface
class X implements Y { } // this is saying that "X" agrees to speak language "Y" with your code.

// abstract class
class X extends Y { } // this is saying that "X" is going to complete the partial class "Y".
?>

Comment puis-je changer ma classe abstraite en une interface?

Voici un cas / exemple simplifié. Retirez tous les détails de mise en œuvre. Par exemple, changez votre classe abstraite de:

abstract class ClassToBuildUpon {
    public function doSomething() {
          echo 'Did something.';
    }
}

à:

interface ClassToBuildUpon {
    public function doSomething();
}
bg17aw
la source
12

D'un point de vue phylosophique:

  • Une classe abstraite représente une relation «est une». Disons que j'ai des fruits, eh bien j'aurais une classe abstraite Fruit qui partage des responsabilités et des comportements communs.

  • Une interface représente une relation "devrait faire". Une interface, à mon avis (qui est l'opinion d'un développeur junior), devrait être nommée par une action, ou quelque chose de proche d'une action, (Désolé, je ne trouve pas le mot, je ne suis pas un locuteur natif anglais) disons IEatable. Vous savez qu'il peut être mangé, mais vous ne savez pas ce que vous mangez.

Du point de vue du codage:

  • Si vos objets ont du code dupliqué, cela indique qu'ils ont un comportement commun, ce qui signifie que vous pourriez avoir besoin d'une classe abstraite pour réutiliser le code, ce que vous ne pouvez pas faire avec une interface.

  • Une autre différence est qu'un objet peut implémenter autant d'interfaces que vous le souhaitez, mais vous ne pouvez avoir qu'une seule classe abstraite en raison du "problème diamant" (consultez ici pour savoir pourquoi! Http://en.wikipedia.org/wiki/ Multiple_inheritance # The_diamond_problem )

J'oublie probablement certains points, mais j'espère que cela pourra clarifier les choses.

PS: Le "est un" / "devrait faire" est apporté par la réponse de Vivek Vermani, je ne voulais pas voler sa réponse, juste pour réutiliser les termes parce que je les aimais!

IEatBagels
la source
2
Le mot que vous cherchez est comestible, je crois.
Travis Weston
1
En fait, je crois que c'est un "Verbe", un "faire un mot"
Grizly
7

Les différences techniques entre une classe abstraite et une interface sont déjà répertoriées avec précision dans les autres réponses. Je veux ajouter une explication pour choisir entre une classe et une interface tout en écrivant le code pour le bien de la programmation orientée objet.

Une classe doit représenter une entité tandis qu'une interface doit représenter le comportement.

Prenons un exemple. Un écran d'ordinateur est une entité et doit être représenté comme une classe.

class Monitor{
    private int monitorNo;
}

Il est conçu pour vous fournir une interface d'affichage, donc la fonctionnalité doit être définie par une interface.

interface Display{
    void display();
}

Il y a beaucoup d'autres choses à considérer comme expliqué dans les autres réponses, mais c'est la chose la plus fondamentale que la plupart des gens ignorent lors du codage.

Anurag Sharma
la source
2
PHP ne définit pas les types de retour et l'OP a marqué cette question avecPHP
Purefan
1

Je voulais juste ajouter un exemple de cas où vous pourriez avoir besoin d'utiliser les deux. J'écris actuellement un gestionnaire de fichiers lié à un modèle de base de données dans une solution ERP à usage général.

  • J'ai plusieurs classes abstraites qui gèrent le crud standard et aussi certaines fonctionnalités spécialisées comme la conversion et le streaming pour différentes catégories de fichiers.
  • L'interface d'accès aux fichiers définit un ensemble commun de méthodes nécessaires pour obtenir, stocker et supprimer un fichier.

De cette façon, j'arrive à avoir plusieurs modèles pour différents fichiers et un ensemble commun de méthodes d'interface avec une distinction claire. L'interface donne l'analogie correcte aux méthodes d'accès plutôt qu'à ce qui aurait été avec une classe abstraite de base.

Plus loin, lorsque je ferai des adaptateurs pour différents services de stockage de fichiers, cette implémentation permettra à l'interface d'être utilisée ailleurs dans des contextes totalement différents.

Umair Ahmed
la source