web-dev-qa-db-fra.com

Interface ou une classe abstraite: lequel utiliser?

S'il vous plaît expliquer quand je dois utiliser un PHP interface et quand je dois utiliser un abstract class?

Comment puis-je changer mon abstract class dans un interface?

306
user220758

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

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

Il ne faut pas oublier non plus que les classes client ne peuvent étendre qu'une classe abstraite, alors qu'elles peuvent implémenter plusieurs interfaces. Ainsi, 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 voulez forcer vos utilisateurs-programmeurs sur un chemin particulier. D'autres fois, ce serait mauvais. Imaginez si les interfaces PHP Countable et Iterator de PHP étaient des classes abstraites au lieu d'interfaces.

Une approche courante lorsque vous ne savez pas quel chemin utiliser (comme indiqué par cletus ci-dessous ) consiste à créer une interface et à laisser votre classe abstraite l'implémenter.

440
Alan Storm

Les différences entre un Abstract Class et un Interface:

classes abstraites

Une classe abstraite peut fournir certaines fonctionnalités et laisser le reste pour 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 être logiquement liée.

Interface

Une interface ne peut contenir aucune fonctionnalité . Il uniquement contient les 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.

155
kn3l

Pourquoi utiliser des classes abstraites? Ce qui suit est 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 un Apple et vous le 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 ce goût? Eh bien, cela n’a pas beaucoup de sens, vous ne devriez donc pas pouvoir le faire. Ceci est accompli en rendant la classe Fruit abstraite 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 qu'elles sont toutes abstraites dans une interface. Les classes abstraites peuvent avoir des méthodes vides et de travail/concrètes. Dans les interfaces, les fonctions définies ne peuvent pas avoir de corps. Dans les classes abstraites, ils 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 
120
Vineesh Kalarickal

La meilleure pratique consiste à utiliser une interface pour spécifier le contrat et une classe abstraite comme une de ses implémentations. 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 que vous souhaitez sans vous obliger à utiliser une implémentation particulière.

63
cletus

Juste pour jeter cela dans le mélange, mais comme Cletus a mentionné l’utilisation d’une interface en conjonction avec une classe abstraite, j’utilise souvent l’interface pour clarifier ma conception.

Par exemple:

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

Ainsi, quiconque lira mon code (et qui sait ce qu'est un motif de décorateur) saura tout de suite a) comment je construis mon analyseur et b) être capable de voir les méthodes utilisées pour mettre en œuvre le motif de décorateur.

De plus, je ne suis peut-être pas au courant ici, je ne suis 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 est important par programmation. Le déplacement de vos éléments contractables dans l'interface dicte uniquement les types que les méthodes renvoient, mais pas le type de base de la classe qui l'implémente.

Il est tard et je ne vois pas de 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)
37
Austen Hoogen

La principale différence est qu'une classe abstraite peut contenir une implémentation par défaut alors qu'une interface ne le peut pas.

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

13
Mitch Wheat

En outre, je voudrais juste ajouter ici que le fait que tout autre langage OO ait une sorte d'interface et que l'abstraction ne signifie pas non plus qu'ils ont le même sens et le même objectif que PHP. L'utilisation d'abstraction/interfaces est légèrement différente alors que les interfaces dans PHP n'ont en réalité pas de fonction réelle. Ils sont simplement utilisés pour des raisons sémantiques et liées aux schémas. Le but est d’avoir un projet aussi flexible que possible, extensible et sûr pour les extensions futures, que le développeur ait ultérieurement un plan d’utilisation totalement différent ou non.

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

Et cela pourrait vous aider en tant que métaphore:

INTERFACE

Supposons que vous prépariez un nouveau type de gâteau aux fraises et que vous prépariez une recette décrivant les ingrédients et les étapes. Vous seul savez pourquoi il goûte si bien et vos invités l’aiment bien. Ensuite, vous décidez de publier votre recette afin que d’autres personnes puissent également essayer ce gâteau.

Le point ici est

- pour arranger ça
- faire attention
- pour éviter des choses qui pourraient aller mal (comme trop de fraises ou quelque chose comme ça)
- pour que ce soit facile pour les personnes qui l'essaient
- pour vous dire combien de temps il faut faire (comme stiring)
- pour dire ce que vous POUVEZ faire mais que vous n'êtes pas obligé de faire

C’est précisément ce qui décrit les interfaces. C'est un guide, un ensemble d'instructions qui respectent le contenu de la recette. Comme si vous créiez un projet dans PHP et que vous souhaitiez fournir le code sur GitHub ou avec vos amis, etc. Une interface est ce que les gens peuvent faire et ce que vous ne devriez pas. Les règles qui la tiennent - si vous en désobéissez, toute la construction sera brisée.


ABSTRACTION

Pour continuer avec cette métaphore ici ... imaginez, vous êtes l'invité cette fois-ci en train de manger ce gâteau. Ensuite, vous essayez ce gâteau en utilisant la recette maintenant. Mais vous souhaitez ajouter de nouveaux ingrédients ou modifier/ignorer 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-ci avec des baies noires et non des baies de paille et plus de crème à la vanille ... miam.

C'est ce que vous pourriez envisager 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 Black Berry contient certaines parties de l'original. Ce sont les étapes de base que chaque sorte de gâteau doit avoir. Comme des ingrédients comme du lait - c’est ce que chaque classe dérivée a.

Maintenant, vous voulez échanger des ingrédients et des étapes et celles-ci DOIVENT être définies dans la nouvelle version de ce gâteau. Ce sont 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? Donc, vous prenez les baies noires cette fois. Terminé.

Voilà, vous avez étendu le gâteau, suivi l'interface et résumé les étapes et les ingrédients qui en découlent.

13
Thielicious

D'un point de vue phylosophique:

  • Une classe abstraite représente une relation "est un". Disons que j'ai des fruits, eh bien, j'aurais une classe abstraite de fruits qui partage des responsabilités et un comportement 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é, impossible de trouver le mot, je ne suis pas un anglophone) permet de dire IEatable. Vous savez que cela 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 aurez peut-être besoin d'une classe abstraite pour réutiliser le code, ce que vous ne pouvez pas utiliser avec une interface.

  • Une autre différence est qu’un objet peut implémenter autant d’interfaces que nécessaire, mais vous ne pouvez avoir qu’une seule classe abstraite à cause du "problème de diamant" (voyez ici pour savoir pourquoi! http: //en.wikipedia. org/wiki/Multiple_inheritance # The_diamond_problem )

J'ai probablement oublié 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!

10
IEatBagels

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 des modèles purs. Une interface ne peut définir que fonctionnalité, elle ne peut jamais la mettre en œuvre.

  • 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 la promesse d'une classe d'implémenter autant d'interfaces que vous le souhaitez.

  • type: pour chaque interface implémentée, la classe prend le type correspondant. Comme toute classe peut implémenter une interface (ou plusieurs interfaces), les interfaces joignent efficacement les types qui ne sont par ailleurs pas liés.

  • une classe peut à la fois étendre une super-classe et implémenter un nombre quelconque d'interfaces:

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

S'il vous plaît expliquer quand je devrais utiliser une interface et quand je devrais utiliser abstract class?

Utilisez une interface lorsque vous ne devez fournir qu'un modèle, sans aucune implémentation, et que vous voulez vous assurer que toute classe implémentant 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 je peux changer ma classe abstraite dans une interface?

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

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

à:

interface ClassToBuildUpon {
    public function doSomething();
}
10
bg17aw

Les différences techniques entre une classe abstraite et une interface sont déjà énumérées avec précision dans les autres réponses. Je veux ajouter une explication pour choisir entre une classe et une interface lors de l’écriture du code dans l’intérêt de la programmation orientée objet.

Une classe devrait représenter une entité alors qu'une interface devrait 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. La fonctionnalité doit donc être définie par une interface.

interface Display{
    void display();
}

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

6
rags147

Je voulais juste ajouter un exemple du moment où vous devrez peut-être utiliser les deux. J'écris actuellement un gestionnaire de fichiers lié à un modèle de base de données dans une solution générale ERP.

  • J'ai plusieurs classes abstraites qui gèrent le format standard, ainsi que des fonctionnalités spéciales telles que la conversion et la diffusion en continu 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, je peux 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 que ce qui aurait été avec une classe abstraite de base.

Plus tard, lorsque je créerai 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.

1
Umair Ahmed