Les 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.
Classes abstraites 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 est basé le matériel 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 jonchés dans la classe abstraite? Suis-je en train de manquer quelque chose?
Réponses:
L'intérêt des interfaces est de vous donner la flexibilité de forcer votre classe à implémenter plusieurs interfaces, mais ne pas autoriser l'héritage multiple. Les problèmes d'héritage de plusieurs classes sont nombreux et variés et la page wikipedia qui les résume assez bien.
Les interfaces sont un compromis. La plupart des problèmes d'héritage multiple ne s'appliquent pas aux classes de base abstraites, de sorte que la plupart des langages modernes désactivent l'héritage multiple tout en appelant des interfaces de classes de base abstraites et permettent à une classe "d'implémenter" autant de ceux qu'ils le souhaitent.
la source
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 "interfacer". En ce qui concerne les classes abstraites, je les considère comme plus de classes de base qui suppriment certaines méthodes et j'ai besoin de remplir les détails.
la source
Pourquoi auriez-vous besoin d'une interface, s'il existe déjà des classes abstraites? Pour éviter l'héritage multiple (peut provoquer plusieurs problèmes connus).
Un de ces problèmes:
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 de voiture aurait ces "méthodes" différentes d'une autre marque. BMW aurait les freins sur le côté droit, et Honda aurait les freins sur le côté gauche de la roue. Les gens devraient apprendre comment ces "méthodes" fonctionnent à chaque fois qu'ils achètent une marque de voiture différente. C'est pourquoi c'est une bonne idée d'avoir la même interface dans plusieurs "endroits".Que fait une interface pour vous (pourquoi quelqu'un en utiliserait-il une)? Une interface vous empêche de faire des "erreurs" (elle vous assure que toutes les classes qui implémentent une interface spécifique, auront toutes les méthodes qui sont dans l'interface).
De cette façon, la
Create()
méthode sera toujours utilisée de la même manière. Peu importe si nous utilisons laMySqlPerson
classe ou leMongoPerson
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):
De cette façon, quelque chose comme ça ne peut pas arriver:
Il est beaucoup plus facile de se souvenir d'une interface et d'utiliser la même partout, que de plusieurs différentes.
De cette façon, l'intérieur de la
Create()
méthode peut être différent 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éthodeCreate()
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 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 empêche 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 l'IPersonService
interface aura la méthodeCreate()
(dans cet exemple) et n'aura besoin que de 1 paramètre ($personObject
) pour être appelée / utilisée.Une classe qui implémente une interface doit implémenter toutes les méthodes que l'interface possède / possède.
J'espère que je ne me suis pas trop répété.
la source
La différence entre l'utilisation d'une interface et d'une classe abstraite a plus à voir avec l'organisation du code que l'application par le langage lui-même. Je les utilise beaucoup lors de la préparation de code pour que d'autres développeurs puissent 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 qui peuvent provenir de code auquel vous n'avez pas accès.
Alors que l'héritage de la classe abstraite est une relation "est une", ce n'est pas toujours ce que vous voulez, et l'implémentation d'une interface est plus une relation "agit comme une" Cette différence peut être assez importante dans certains contextes.
Par exemple, disons que vous avez un compte de classe abstraite à partir duquel de nombreuses autres classes s'étendent (types de comptes, etc.). Il a un ensemble particulier de méthodes qui ne s'appliquent qu'à ce groupe de types. Cependant, certaines de ces sous-classes de comptes implémentent Versionable, Listable ou Editable afin qu'elles puissent être lancées dans des contrôleurs qui s'attendent à 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 depuis 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 à partir 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 elle-même 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.
la source
Les interfaces sont essentiellement un modèle pour ce que vous pouvez créer. Ils définissent les méthodes qu'une classe doit avoir , mais vous pouvez créer des méthodes supplémentaires en dehors de ces limitations.
Je ne sais pas 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 dans 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 que d'être implémentée 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 pensé aux interfaces comme un modèle pour les développeurs externes ou un ensemble de règles supplémentaire pour garantir que les choses sont correctes.
la source
Vous utiliserez des interfaces en PHP:
$object instanceof MyInterface
Car
objet peut maintenantstart()
,stop()
(EngineInterface) ougoRight()
,goLeft()
(Interface de direction)et d'autres choses auxquelles je ne peux pas penser en ce moment
Le numéro 4 est probablement le cas d'utilisation le plus évident que vous ne pouvez pas aborder avec des classes abstraites.
De Penser en Java:
la source
Les interfaces existent non 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 convient 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 ont toutes les méthodes publiques communes dont mon application a besoin pour obtenir les données.
Ensuite, lorsqu'un utilisateur ajoute un nouveau flux, je peux identifier le type de flux qu'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, sinon il pourrait y avoir très peu de similitudes entre les classes en dehors du fait qu'elles sont requises 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 outrepassé la méthode getEvents () qui casserait alors mon application dans ce cas, alors que l'utilisation d'une interface ne laisserait pas mon application s'exécuter si l'une des méthodes définies dans l'interface n'existent pas dans la classe qui l'a implémentée. Mon application n'a pas à se soucier de la classe qu'elle utilise pour obtenir les données d'un flux,
Pour aller plus loin, l'interface se révèle 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 de volume à mon application principale, car mon application principale ne dépend que des méthodes publiques disponibles dont l'interface a besoin, tant que mes nouvelles classes d'importation de flux implémentent l'interface ImportableFeed, puis je sais que je peux simplement le laisser en place et continuer à bouger.
Ce n'est qu'un début très simple. Je peux ensuite créer une autre interface que toutes mes classes d'agenda peuvent être tenues d'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 pour vérifier le type de flux, etc.
Cela va au-delà de la question, mais puisque j'ai utilisé l'exemple ci-dessus: les interfaces sont livrées avec leur propre ensemble de problèmes si elles sont utilisées de cette manière. Je me retrouve à avoir besoin d'assurer la sortie qui est retournée par les méthodes implémentées pour correspondre à 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 dans 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:
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 ait un ensemble d'interfaces publiques.
la source
Les interfaces ne sont pas seulement destinées à garantir que les développeurs implémentent certaines méthodes. L'idée est que parce que ces classes sont garanties d'avoir certaines méthodes, vous pouvez utiliser ces méthodes même si vous ne connaissez pas le type réel de la classe. Exemple:
Dans de nombreux cas, il n'est pas logique de fournir une classe de base, abstraite ou non, car les implémentations varient énormément et ne partagent rien en plus de quelques méthodes.
Les langages typés dynamiquement ont la notion de "typage de 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.
la source
À mon avis, les interfaces devraient être préférées aux classes abstraites non fonctionnelles. Je ne serais pas surpris s'il y aurait même un impact sur les performances, car il n'y a qu'un seul objet instancié, au lieu d'analyser deux, de les combiner (bien que, je ne peux pas être sûr, je ne suis pas familier avec le fonctionnement interne de OOP 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: interfaces définit 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 à des besoins spécifiques.
la source
En PHP, vous pouvez appliquer plusieurs interfaces en les séparant par une virgule (je pense, je ne trouve pas cela une solution propre).
En ce qui concerne plusieurs classes abstraites, vous pouvez avoir plusieurs résumés s'étendant les uns aux autres (encore une fois, je ne suis pas totalement sûr de cela, mais je pense avoir déjà vu cela quelque part auparavant). La seule chose que vous ne pouvez pas prolonger est une classe finale.
la source
Les interfaces ne donneront à votre code aucune amélioration des performances ou quelque chose comme ça, 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 à trier et lire.
Cela étant dit, j'ai tendance à faire preuve de discrétion pour décider d'utiliser ou non une interface sur une classe. Parfois, je veux des implémentations de méthodes par défaut, ou des variables qui seront communes à toutes les sous-classes.
Bien sûr, le point sur la mise en œuvre de plusieurs interfaces est également valable. Si vous avez 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, cependant, rend les choses un peu plus intéressantes. Taper sur les interfaces n'est toujours pas incroyablement nécessaire en PHP, où vous pouvez à peu près tout alimenter 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 hoquets). Ajoutez à cela le fait que vous ne pouvez pas taper la plupart des autres références, et il n'y a pas beaucoup de valeur à essayer de forcer la saisie statique en PHP ( à ce stade ). Et à cause de cela, la valeur des interfaces en PHP , à ce stadeest beaucoup moins que dans les langues plus fortement typées. Ils ont l'avantage de la lisibilité, mais pas grand-chose 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 dans l'implémenteur.
la source
Voici les points pour l'interface PHP
Exemple de code:
la source
Nous avons vu que les classes abstraites et les interfaces sont similaires en ce qu'elles fournissent des méthodes abstraites qui doivent être implémentées dans les classes enfants. Cependant, ils présentent toujours les différences suivantes:
J'espère que cela vous aidera à comprendre!
la source
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 des classes abstraites vs interfaces, ce qui est hérité est plus spécifique.
la source
Je ne connais pas les autres langues, quel est le concept d'interface là-bas. Mais pour PHP, je ferai de mon mieux pour l'expliquer. Soyez patient et veuillez commenter si cela a aidé.
La règle
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 ont la même méthode de parole, mais avec des fonctionnalités ou une mise en œuvre différentes. Supposons que nous donnons à l'utilisateur une télécommande dotée d'un bouton de prise de parole.
C'est un bon cas pour utiliser une interface, pas une classe abstraite car les implémentations sont différentes. Pourquoi? Rappelles 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.
la source