À la demande d'exizt, j'élargis mon commentaire à une réponse plus longue.
La plus grande erreur que les gens commettent est de croire que les interfaces sont simplement des classes abstraites vides. Une interface est un moyen pour un programmeur de dire: "Je me fiche de ce que vous me donnez, tant qu'il suit cette convention."
La bibliothèque .NET est un merveilleux exemple. Par exemple, lorsque vous écrivez une fonction qui accepte un IEnumerable<T>
, ce que vous dites est: «Je me fiche de la façon dont vous stockez vos données. Je veux juste savoir que je peux utiliser une foreach
boucle.
Cela conduit à un code très flexible. Du coup pour être intégré, il suffit de respecter les règles des interfaces existantes. Si la mise en œuvre de l'interface est difficile ou déroutante, c'est peut-être un indice que vous essayez de pousser une cheville carrée dans un trou rond.
Mais la question se pose alors: "Qu'en est-il de la réutilisation du code? Mes professeurs CS m'ont dit que l'héritage était la solution à tous les problèmes de réutilisation du code et que l'héritage vous permet d'écrire une fois et de l'utiliser partout et qu'il guérirait la ménangite en train de sauver des orphelins des mers montantes et il n'y aurait plus de larmes et ainsi de suite etc. etc. etc. "
Utiliser l'héritage simplement parce que vous aimez le son des mots "réutilisation de code" est une très mauvaise idée. Le guide de style de code de Google explique ce point de manière assez concise:
La composition est souvent plus appropriée que l'héritage. ... [B] car le code implémentant une sous-classe est réparti entre la base et la sous-classe, il peut être plus difficile de comprendre une implémentation. La sous-classe ne peut pas remplacer les fonctions qui ne sont pas virtuelles, donc la sous-classe ne peut pas modifier l'implémentation.
Pour illustrer pourquoi l'héritage n'est pas toujours la réponse, je vais utiliser une classe appelée MySpecialFileWriter †. Une personne qui croit aveuglément que l'héritage est la solution à tous les problèmes dirait que vous devriez essayer d'hériter FileStream
, de peur de dupliquer FileStream
le code de. Les gens intelligents reconnaissent que c'est stupide. Vous devez simplement avoir un FileStream
objet dans votre classe (en tant que variable locale ou membre) et utiliser ses fonctionnalités.
L' FileStream
exemple peut sembler artificiel, mais ce n'est pas le cas. Si vous avez deux classes qui implémentent la même interface de la même manière, vous devez avoir une troisième classe qui encapsule toute opération dupliquée. Votre objectif devrait être d'écrire des classes qui sont des blocs réutilisables autonomes qui peuvent être assemblés comme des legos.
Cela ne signifie pas que l'héritage doit être évité à tout prix. Il y a de nombreux points à considérer, et la plupart seront couverts par la recherche de la question, "Composition vs héritage". Notre propre Stack Overflow a quelques bonnes réponses à ce sujet.
À la fin de la journée, les sentiments de votre collègue manquent de profondeur ou de compréhension nécessaires pour prendre une décision éclairée. Recherchez le sujet et découvrez-le par vous-même.
† Pour illustrer l'héritage, tout le monde utilise des animaux. C'est inutile. En 11 ans de développement, je n'ai jamais écrit de classe nommée Cat
, donc je ne vais pas l'utiliser comme exemple.
alligator
La mise en œuvre deeat
diffère, bien sûr, en ce qu'elle acceptecat
et endog
tant que paramètres.