Je suis encore à des années de saisir pleinement la distinction entre une classe abstraite et une interface. Chaque fois que je pense maîtriser les concepts de base, je vais chercher sur stackexchange et je suis à deux pas en arrière. Mais quelques réflexions sur le sujet et la question des PO:
Première:
Il existe deux explications courantes d'une interface:
Une interface est une liste de méthodes et de propriétés que n'importe quelle classe peut implémenter, et en implémentant une interface, une classe garantit que ces méthodes (et leurs signatures) et ces propriétés (et leurs types) seront disponibles lors de "l'interfaçage" avec cette classe ou un objet de cette classe. Une interface est un contrat.
Les interfaces sont des classes abstraites qui ne font / ne peuvent rien faire. Ils sont utiles car vous pouvez en implémenter plusieurs, contrairement à ces classes parentales moyennes. Par exemple, je pourrais être un objet de la classe BananaBread et hériter de BaseBread, mais cela ne signifie pas que je ne peux pas également implémenter les interfaces IWithNuts et ITastesYummy. Je pourrais même implémenter l'interface IDoesTheDishes, parce que je ne suis pas seulement du pain, vous savez?
Il existe deux explications courantes d'une classe abstraite:
Une classe abstraite est, yknow, la chose pas ce que la chose peut faire. C'est comme, l'essence, pas vraiment une chose réelle du tout. Attendez, cela vous aidera. Un bateau est une classe abstraite, mais un Playboy Yacht sexy serait une sous-classe de BaseBoat.
J'ai lu un livre sur les classes abstraites, et peut-être devriez-vous lire ce livre, parce que vous ne le comprenez probablement pas et le ferez mal si vous ne l'avez pas lu.
Soit dit en passant, le livre Citers semble toujours impressionnant, même si je m'en vais encore confus.
Seconde:
Sur SO, quelqu'un a demandé une version plus simple de cette question, le classique, "pourquoi utiliser des interfaces? Quelle est la différence? Qu'est-ce que je manque?" Et une réponse a utilisé un pilote de l'armée de l'air comme exemple simple. Il n'a pas tout à fait atterri, mais il a suscité de grands commentaires, dont l'un a mentionné l'interface IFlyable ayant des méthodes comme takeOff, pilotEject, etc. Et cela a vraiment cliqué pour moi comme un exemple concret de la raison pour laquelle les interfaces ne sont pas seulement utiles, mais crucial. Une interface rend un objet / classe intuitif, ou du moins donne le sentiment qu'il l'est. Une interface n'est pas au profit de l'objet ou des données, mais pour quelque chose qui doit interagir avec cet objet. Le classique Fruit-> Apple-> Fuji ou Shape-> Triangle-> Les exemples équilatéraux d'héritage sont un excellent modèle pour comprendre taxonomiquement un objet donné en fonction de ses descendants. Il informe le consommateur et les processeurs de ses qualités générales, de ses comportements, que l'objet soit un groupe de choses, arrosera votre système si vous le placez au mauvais endroit, ou décrit des données sensorielles, un connecteur vers un magasin de données spécifique, ou données financières nécessaires pour faire la paie.
Un objet Plane spécifique peut ou non avoir une méthode pour un atterrissage d'urgence, mais je vais être énervé si j'assume son emergencyLand comme tout autre objet volant uniquement pour se réveiller couvert dans DumbPlane et apprendre que les développeurs sont allés avec quickLand parce qu'ils pensaient que c'était pareil. Tout comme je serais frustré si chaque fabricant de vis avait sa propre interprétation de Righty tighty ou si mon téléviseur n'avait pas le bouton d'augmentation du volume au-dessus du bouton de diminution du volume.
Les classes abstraites sont le modèle qui établit ce que tout objet descendant doit posséder pour être qualifié de classe. Si vous n'avez pas toutes les qualités d'un canard, peu importe que vous ayez l'interface IQuack implémentée, votre juste un pingouin bizarre. Les interfaces sont des choses qui ont du sens même lorsque vous ne pouvez être sûr de rien d'autre. Jeff Goldblum et Starbuck étaient tous deux capables de piloter des vaisseaux spatiaux extraterrestres parce que l'interface était fiable de manière similaire.
Troisième:
Je suis d'accord avec votre collègue, car parfois vous devez appliquer certaines méthodes au tout début. Si vous créez un ORM d'enregistrement actif, il a besoin d'une méthode de sauvegarde. Ce n'est pas à la hauteur de la sous-classe qui peut être instanciée. Et si l'interface ICRUD est suffisamment portable pour ne pas être exclusivement couplée à la seule classe abstraite, elle peut être implémentée par d'autres classes pour les rendre fiables et intuitives pour toute personne déjà familière avec l'une des classes descendantes de cette classe abstraite.
D'un autre côté, il y avait un excellent exemple plus tôt de ne pas sauter pour lier une interface à la classe abstraite, car tous les types de liste n'implémenteront pas (ou ne devraient pas) implémenter une interface de file d'attente. Vous avez dit que ce scénario se produit la moitié du temps, ce qui signifie que vous et votre collègue avez tous les deux tort la moitié du temps, et donc la meilleure chose à faire est d'argumenter, de débattre, de considérer, et s'ils s'avèrent corrects, reconnaissez et acceptez le couplage . Mais ne devenez pas un développeur qui suit une philosophie même si elle n'est pas la meilleure pour le travail à accomplir.