Veuillez expliquer quand utiliser un PHP interface
et quand utiliser un abstract class
?
Comment puis-je changer mon entrée abstract class
en un interface
?
Veuillez expliquer quand utiliser un PHP interface
et quand utiliser un abstract class
?
Comment puis-je changer mon entrée abstract class
en un interface
?
Réponses:
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.
Les différences entre un Abstract Class
et 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.
abstract class X implements Y
et class X implements Y
?
abstract class X implements Y
vous 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 Y
que 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.
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
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!
final
mot-clé? Excellent article, merci.
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.
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)
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.
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();
}
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!
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.
PHP
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.
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.
abstract
et lesinterface
cours, votre message a été clair. Merci beaucoup Alan