Question

Interfaces vous permettent de créer du code qui définit les méthodes des classes qui l'implémentent.Vous ne pouvez cependant pas ajouter de code à ces méthodes.

Cours abstraits vous permettent de faire la même chose, tout en ajoutant du code à la méthode.

Maintenant, si vous pouvez atteindre le même objectif avec des classes abstraites, pourquoi avons-nous même besoin du concept d’interfaces ?

On m'a dit que cela avait à voir avec la théorie OO de C++ à Java, sur laquelle sont basés les éléments OO de PHP.Le concept est-il utile en Java mais pas en PHP ?Est-ce juste un moyen d'éviter d'avoir des espaces réservés dans la classe abstraite ?Est-ce que j'ai raté quelque chose ?

Était-ce utile?

La solution

L’intérêt des interfaces est de vous donner la flexibilité de forcer votre classe à implémenter plusieurs interfaces, sans pour autant autoriser l’héritage multiple.Les problèmes liés à l'héritage de plusieurs classes sont nombreux et variés. Wikipédia la page dessus les résume assez bien.

Les interfaces sont un compromis.La plupart des problèmes liés à l'héritage multiple ne s'appliquent pas aux classes de base abstraites, donc la plupart des langages modernes désactivent aujourd'hui l'héritage multiple mais appellent des interfaces de classes de base abstraites et permettent à une classe d'"implémenter" autant d'entre elles qu'elle le souhaite.

Autres conseils

Le concept est utile partout dans la programmation orientée objet.Pour moi, je considère une interface comme un contrat.Tant que ma classe et votre classe sont d'accord sur ce contrat de signature de méthode, nous pouvons "interagir".En ce qui concerne les classes abstraites, je les considère davantage comme des classes de base qui suppriment certaines méthodes et dont je dois remplir les détails.

Pourquoi auriez-vous besoin d’une interface, s’il existe déjà des classes abstraites ?Pour empêcher l'héritage multiple (peut provoquer plusieurs problèmes connus).

Un de ces problèmes :

Le "problème de diamant" (parfois appelé "diamant mortel de la mort") est une ambiguïté qui survient lorsque deux classes B et C héritent de A et de la classe D héritent de B et C.S'il existe une méthode dans A que B et C ont remplacé, et D ne l'emporte pas, alors quelle version de la méthode D hérite:celui de B, ou celui de C ?

Source: https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem

Pourquoi/Quand utiliser une interface ?Un exemple...Toutes les voitures du monde ont la même interface (méthodes)... AccelerationPedalIsOnTheRight(), BrakePedalISOnTheLeft().Imaginez que chaque marque automobile aurait ces « méthodes » différentes d’une autre marque.BMW aurait les freins du côté droit et Honda aurait des freins du côté gauche de la roue.Les gens devraient apprendre comment fonctionnent ces « méthodes » chaque fois qu’ils achèteraient une marque de voiture différente.C'est pourquoi c'est une bonne idée d'avoir la même interface à plusieurs « endroits ».

Que fait une interface pour vous (pourquoi quelqu’un en utiliserait-il une) ?Une interface vous évite de faire des "erreurs" (elle vous assure que toutes les classes qui implémentent une interface spécifique auront toutes les méthodes qui se trouvent dans l'interface).

// Methods inside this interface must be implemented in all classes which implement this interface.
interface IPersonService
{   
    public function Create($personObject);
}

class MySqlPerson implements IPersonService
{
    public function Create($personObject)
    {
        // Create a new person in MySql database.
    }
}

class MongoPerson implements IPersonService
{
    public function Create($personObject)
    {
        // Mongo database creates a new person differently then MySQL does. But the code outside of this method doesn't care how a person will be added to the database, all it has to know is that the method Create() has 1 parameter (the person object).
    }
}

De cette façon, le Create() la méthode sera toujours utilisée de la même manière.Peu importe si nous utilisons le MySqlPerson classe ou le MongoPerson classe.La façon dont nous utilisons une méthode reste la même (l'interface reste la même).

Par exemple, il sera utilisé comme ceci (partout dans notre code) :

new MySqlPerson()->Create($personObject);
new MongoPerson()->Create($personObject);

De cette façon, quelque chose comme ceci ne peut pas arriver :

new MySqlPerson()->Create($personObject)
new MongoPerson()->Create($personsName, $personsAge);

Il est beaucoup plus facile de mémoriser une interface et d'utiliser la même partout que plusieurs interfaces différentes.

De cette façon, l'intérieur du Create() La méthode peut être différente pour différentes classes, sans affecter le code "extérieur" qui appelle cette méthode.Tout ce que le code extérieur doit savoir, c'est que la méthode Create() a 1 paramètre ($personObject), car c'est ainsi que le code extérieur utilisera/appellera la méthode.Le code extérieur ne se soucie pas de ce qui se passe à l'intérieur de la méthode ;il lui suffit de savoir comment l'utiliser/l'appeler.

Vous pouvez également le faire sans interface, mais si vous utilisez une interface, c'est "plus sûr" (car cela vous évite de faire des erreurs).L'interface vous assure que la méthode Create() aura la même signature (mêmes types et même nombre de paramètres) dans toutes les classes qui implémentent l'interface.De cette façon, vous pouvez être sûr que TOUTE classe qui implémente le IPersonService interface, aura la méthode Create() (dans cet exemple) et n'aura besoin que d'un seul paramètre ($personObject) pour être appelé/utilisé.

Une classe qui implémente une interface doit implémenter toutes les méthodes que l'interface fait/possède.

J'espère que je ne me suis pas trop répété.

La différence entre l'utilisation d'une interface et d'une classe abstraite a plus à voir avec l'organisation du code qu'avec l'application par le langage lui-même.Je les utilise beaucoup lors de la préparation du code avec lequel d'autres développeurs pourront travailler afin qu'ils restent dans les modèles de conception prévus.Les interfaces sont une sorte de « conception par contrat » par laquelle votre code accepte de répondre à un ensemble prescrit d'appels d'API pouvant provenir d'un code auquel vous n'avez pas accès.

Bien que l'héritage d'une classe abstraite soit une relation "est une", ce n'est pas toujours ce que vous voulez, et l'implémentation d'une interface est plutôt une relation "agit comme une".Cette différence peut être assez significative dans certains contextes.

Par exemple, disons que vous disposez d'une classe abstraite Account à partir de laquelle s'étendent de nombreuses autres classes (types de comptes, etc.).Il dispose d'un ensemble particulier de méthodes qui ne sont applicables qu'à ce groupe de types.Cependant, certaines de ces sous-classes de comptes implémentent Versionable, Listable ou Editable afin de pouvoir être lancées dans des contrôleurs qui prévoient d'utiliser ces API.Le contrôleur ne se soucie pas de quel type d’objet il s’agit

En revanche, je peux également créer un objet qui ne s'étend pas à partir de Account, par exemple une classe abstraite User, et toujours implémenter Listable et Editable, mais pas Versionable, ce qui n'a pas de sens ici.

De cette façon, je dis que la sous-classe FooUser n'est PAS un compte, mais agit comme un objet modifiable.De même, BarAccount s'étend de Account, mais n'est pas une sous-classe User, mais implémente Editable, Listable et également Versionable.

L'ajout de toutes ces API pour Editable, Listable et Versionable dans les classes abstraites elles-mêmes serait non seulement encombré et laid, mais dupliquerait les interfaces communes dans Account et User, ou forcerait mon objet User à implémenter Versionable, probablement juste pour lancer un exception.

Les interfaces sont essentiellement un modèle de ce que vous pouvez créer.Ils définissent quelles méthodes une classe doit avoir, mais vous pouvez créer des méthodes supplémentaires en dehors de ces limitations.

Je ne suis pas sûr de ce que vous entendez par ne pas pouvoir ajouter de code aux méthodes - parce que vous le pouvez.Appliquez-vous l'interface à une classe abstraite ou à la classe qui l'étend ?

Une méthode de l'interface appliquée à la classe abstraite devra être implémentée dans cette classe abstraite.Cependant, appliquez cette interface à la classe d’extension et la méthode n’a besoin d’être implémentée que dans la classe d’extension.Je peux me tromper ici - je n'utilise pas les interfaces aussi souvent que je pourrais/devrais.

J'ai toujours considéré les interfaces comme un modèle pour les développeurs externes ou comme un ensemble de règles supplémentaires pour garantir que les choses sont correctes.

Vous utiliserez des interfaces en PHP :

  1. Pour masquer l'implémentation - établissez un protocole d'accès à une classe d'objets et modifiez l'implémentation sous-jacente sans refactoriser tous les endroits où vous avez utilisé ces objets
  2. Pour vérifier le type - comme pour s'assurer qu'un paramètre a un type spécifique $object instanceof MyInterface
  3. Pour appliquer la vérification des paramètres au moment de l'exécution
  4. Pour implémenter plusieurs comportements dans une seule classe (créer des types complexes)

    la classe Car implémente EngineInterface, BodyInterface, SteeringInterface {

pour qu'un Car objet ca maintenant start(), stop() (InterfaceMoteur) ou goRight(),goLeft() (Interface de pilotage)

et d'autres choses auxquelles je ne peux pas penser pour le moment

Numéro 4, c'est probablement le cas d'utilisation le plus évident que vous ne pouvez pas résoudre avec des classes abstraites.

De Penser en Java :

Une interface dit: «C'est à quoi ressemblera toutes les classes qui implémentent cette interface particulière.» Ainsi, tout code qui utilise une interface particulière sait quelles méthodes peuvent être appelées pour cette interface, et c'est tout.L’interface sert donc à établir un « protocole » entre les classes.

Les interfaces n'existent pas comme une base sur laquelle les classes peuvent s'étendre mais comme une carte des fonctions requises.

Voici un exemple d'utilisation d'une interface dans laquelle une classe abstraite ne rentre pas :
Disons que j'ai une application de calendrier qui permet aux utilisateurs d'importer des données de calendrier à partir de sources externes.J'écrirais des classes pour gérer l'importation de chaque type de source de données (ical, rss, atom, json). Chacune de ces classes implémenterait une interface commune qui garantirait qu'elles disposent toutes des méthodes publiques communes dont mon application a besoin pour obtenir les données.

<?php

interface ImportableFeed 
{
    public function getEvents();
}

Ensuite, lorsqu'un utilisateur ajoute un nouveau flux, je peux identifier de quel type de flux il s'agit et utiliser la classe développée pour ce type pour importer les données.Chaque classe écrite pour importer des données pour un flux spécifique aurait un code complètement différent, il pourrait autrement y avoir très peu de similitudes entre les classes en dehors du fait qu'elles sont nécessaires pour implémenter l'interface qui permet à mon application de les consommer.Si je devais utiliser une classe abstraite, je pourrais très facilement ignorer le fait que je n'ai pas remplacé la méthode getEvents(), ce qui briserait alors mon application dans ce cas, alors que l'utilisation d'une interface ne permettrait pas à mon application de s'exécuter si l'une des méthodes définis dans l’interface n’existent pas dans la classe qui l’a implémenté.Mon application n'a pas besoin de se soucier de la classe qu'elle utilise pour obtenir les données d'un flux, mais seulement de la présence des méthodes dont elle a besoin pour obtenir ces données.

Pour aller plus loin, l'interface s'avère extrêmement utile lorsque je reviens à mon application de calendrier avec l'intention d'ajouter un autre type de flux.L'utilisation de l'interface ImportableFeed signifie que je peux continuer à ajouter plus de classes qui importent différents types de flux en ajoutant simplement de nouvelles classes qui implémentent cette interface.Cela me permet d'ajouter des tonnes de fonctionnalités sans avoir à ajouter inutilement du volume à mon application principale, car mon application principale repose uniquement sur les méthodes publiques disponibles dont l'interface a besoin, donc tant que mes nouvelles classes d'importation de flux implémentent l'interface ImportableFeed, alors je je sais que je peux simplement le laisser en place et continuer à avancer.

Ce n’est qu’un début très simple.Je peux ensuite créer une autre interface que toutes mes classes de calendrier peuvent devoir implémenter et qui offre plus de fonctionnalités spécifiques au type de flux géré par la classe.Un autre bon exemple serait une méthode permettant de vérifier le type d’aliment, etc.

Cela dépasse la question mais puisque j'ai utilisé l'exemple ci-dessus :Les interfaces présentent leur propre ensemble de problèmes si elles sont utilisées de cette manière.Je dois garantir que le résultat renvoyé par les méthodes implémentées correspond à l'interface et pour y parvenir, j'utilise un IDE qui lit les blocs PHPDoc et ajoute le type de retour comme indice de type dans un bloc PHPDoc de l'interface qui sera ensuite traduire à la classe concrète qui l’implémente.Mes classes qui consomment les données de sortie des classes qui implémentent cette interface sauront alors au moins qu'elles attendent un tableau renvoyé dans cet exemple :

<?php
interface ImportableFeed 
{
    /**
     * @return array
     */
    public function getEvents();
}

Il n'y a pas beaucoup de place pour comparer les classes abstraites et les interfaces.Les interfaces sont simplement des cartes qui, une fois implémentées, nécessitent que la classe dispose d'un ensemble d'interfaces publiques.

Les interfaces ne servent pas uniquement à garantir que les développeurs implémentent certaines méthodes.L'idée est que, comme il est garanti que ces classes ont certaines méthodes, vous pouvez utiliser ces méthodes même si vous ne connaissez pas le type réel de la classe.Exemple:

interface Readable {
  String read();
}

List<Readable> readables; // dunno what these actually are, but we know they have read();
for(Readable reader : readables)
  System.out.println(reader.read());

Dans de nombreux cas, cela n'a pas de sens de fournir une classe de base, abstraite ou non, car les implémentations varient énormément et ne partagent rien en commun à part quelques méthodes.

Les langages typés dynamiquement ont la notion de « typage canard » où vous n'avez pas besoin d'interfaces ;vous êtes libre de supposer que l'objet possède la méthode que vous appelez.Cela contourne le problème dans les langages typés statiquement où votre objet a une méthode (dans mon exemple, read()), mais n'implémente pas l'interface.

À mon avis, les interfaces devraient être préférées aux classes abstraites non fonctionnelles.Je ne serais pas surpris s'il y avait ne serait-ce qu'un impact sur les performances, car il n'y a qu'un seul objet instancié, au lieu d'en analyser deux, en les combinant (même si, je ne peux pas en être sûr, je ne suis pas familier avec le fonctionnement interne de la POO PHP).

Il est vrai que les interfaces sont moins utiles/significatives que, par exemple, Java.D'un autre côté, PHP6 introduira encore plus d'indications de type, y compris des indications de type pour les valeurs de retour.Cela devrait ajouter de la valeur aux interfaces PHP.

tl;dr :les interfaces définissent une liste de méthodes qui doivent être suivies (pensez à l'API), tandis qu'une classe abstraite donne des fonctionnalités de base/communes, que les sous-classes affinent en fonction de besoins spécifiques.

Je ne me souviens pas si PHP est différent à cet égard, mais en Java, vous pouvez implémenter plusieurs interfaces, mais vous ne pouvez pas hériter de plusieurs classes abstraites.Je suppose que PHP fonctionne de la même manière.

En PHP, vous pouvez appliquer plusieurs interfaces en les séparant par une virgule (je pense que je ne trouve pas cela une solution propre).

En ce qui concerne plusieurs classes abstraites, vous pouvez avoir plusieurs résumés qui s'étendent les uns aux autres (encore une fois, je n'en suis pas totalement sûr mais je pense l'avoir déjà vu quelque part).La seule chose que vous ne pouvez pas prolonger est un cours final.

Les interfaces n'amélioreront pas les performances de votre code ou quoi que ce soit du genre, mais elles peuvent grandement contribuer à le rendre maintenable.Il est vrai qu'une classe abstraite (ou même une classe non abstraite) peut être utilisée pour établir une interface avec votre code, mais les interfaces appropriées (celles que vous définissez avec le mot-clé et qui ne contiennent que des signatures de méthode) sont tout simplement plus faciles à utiliser. trier et lire.

Cela étant dit, j'ai tendance à faire preuve de discrétion lorsque je décide d'utiliser ou non une interface sur une classe.Parfois, je souhaite des implémentations de méthodes par défaut ou des variables communes à toutes les sous-classes.

Bien entendu, le point concernant l’implémentation de plusieurs interfaces est également pertinent.Si vous disposez d'une classe qui implémente plusieurs interfaces, vous pouvez utiliser un objet de cette classe sous différents types dans la même application.

Le fait que votre question concerne PHP rend les choses un peu plus intéressantes.Taper sur des interfaces n'est toujours pas incroyablement nécessaire en PHP, où vous pouvez à peu près n'importe quoi envoyer à n'importe quelle méthode, quel que soit son type.Vous pouvez taper statiquement des paramètres de méthode, mais certains d'entre eux sont cassés (String, je crois, provoque quelques problèmes).Ajoutez à cela le fait que vous ne pouvez pas taper la plupart des autres références et qu'il n'y a pas beaucoup d'intérêt à essayer de forcer la saisie statique en PHP (à ce point).Et pour cette raison, la valeur des interfaces en PHP, à ce point est bien inférieur à ce qu’il est dans les langues plus fortement typées.Ils ont l’avantage de la lisibilité, mais rien d’autre.L'implémentation multiple n'est même pas bénéfique, car vous devez toujours déclarer les méthodes et leur donner des corps au sein de l'implémenteur.

Les interfaces sont comme vos gènes.

Les cours abstraits sont comme vos vrais parents.

Leurs objectifs sont héréditaires, mais dans le cas de classes abstraites par rapport aux interfaces, ce qui est hérité est plus spécifique.

Voici les points pour l'interface PHP

  1. Il est utilisé pour définir le nombre requis de méthodes dans la classe [si vous souhaitez charger du HTML, l'identifiant et le nom sont requis, donc dans ce cas, l'interface inclut setID et setName].
  2. L'interface force strictement la classe à inclure toutes les méthodes qui y sont définies.
  3. Vous ne pouvez définir une méthode que dans une interface accessible au public.
  4. Vous pouvez également étendre l’interface comme la classe.Vous pouvez étendre l'interface en php en utilisant le mot-clé extends.
  5. Étendre plusieurs interfaces.
  6. Vous ne pouvez pas implémenter 2 interfaces si les deux partagent une fonction portant le même nom.Cela générera une erreur.

Exemple de code :

interface test{
    public function A($i);
    public function B($j = 20);
}

class xyz implements test{
    public function A($a){
        echo "CLASS A Value is ".$a;
    }
    public function B($b){
        echo "CLASS B Value is ".$b;
    }
}
$x = new xyz();
echo $x->A(11);
echo "<br/>";
echo $x->B(10);

Nous avons vu que les classes abstraites et les interfaces sont similaires dans le sens où elles fournissent des méthodes abstraites qui doivent être implémentées dans les classes enfants.Cependant, ils présentent encore les différences suivantes :

1.Les interfaces peuvent inclure des méthodes et des constantes abstraites, mais ne peuvent pas contenir de méthodes et de variables concrètes.

2.Toutes les méthodes de l'interface doivent être dans le publique Portée de visibilité.

3.A Classe peut implémenter plus d'une interface, tandis qu'elle peut hériter d'une seule classe abstraite.

                                  interface                      abstract class
the code                     - abstract methods               - abstract methods
                             - constants                      - constants                  
                                                              - concrete methods
                                                              - concrete variables

access modifiers             
                             - public                         - public
                                                              - protected
                                                              - private
                                                                etc.
number of parents          The same class can implement
                           more than 1 interface              The child class can 
                                                              inherit only from 1 abstract class

J'espère que cela aidera tout le monde à comprendre !

Je ne connais pas les autres langages, quel est le concept d'interface là-bas.Mais pour PHP, je ferai de mon mieux pour l'expliquer.Soyez juste patient et veuillez commenter si cela vous a aidé.

Une interface fonctionne comme un « contrat », spécifiant ce que fait un ensemble de sous-classes, mais pas comment elles le font.

La règle

  1. Une interface ne peut pas être instanciée.

  2. Vous ne pouvez implémenter aucune méthode dans une interface, c'est-à-direil ne contient que la .signature de la méthode mais pas les détails (corps).

  3. Les interfaces peuvent contenir des méthodes et/ou des constantes, mais aucun attribut.Les constantes d'interface ont les mêmes restrictions que les constantes de classe.Les méthodes d'interface sont implicitement abstraites.

  4. Les interfaces ne doivent pas déclarer les constructeurs ou les destructeurs, car ce sont des détails d'implémentation au niveau de la classe.
  5. Toutes les méthodes d'une interface doivent avoir une visibilité publique.

Prenons maintenant un exemple.Supposons que nous ayons deux jouets :l'un est un chien et l'autre est un chat.

Comme nous le savons, un chien aboie et un chat miaule. Ces deux-là ont la même méthode de parole, mais avec des fonctionnalités ou une implémentation différentes.Supposons que nous donnions à l'utilisateur une télécommande dotée d'un bouton de parole.

Lorsque l'utilisateur appuie sur le bouton Parler, le jouet doit parler, peu importe qu'il s'agisse d'un chien ou d'un chat.

C'est un bon cas d'utiliser une interface, pas une classe abstraite car les implémentations sont différentes.Pourquoi?Souviens-toi

Si vous devez prendre en charge les classes enfants en ajoutant une méthode non abstraite, vous devez utiliser des classes abstraites.Sinon, les interfaces seraient votre choix.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top