On m'a appris cela aussi et je préfère les interfaces dans la mesure du possible (bien sûr, j'utilise toujours l'héritage là où c'est logique).
Une des choses que je pense est de dissocier votre code des implémentations spécifiques. Supposons que je possède une classe appelée ConsoleWriter qui est transmise à une méthode pour écrire quelque chose et l’écrit sur la console. Maintenant, disons que je veux passer à l’impression dans une fenêtre graphique. Eh bien, je dois maintenant modifier la méthode ou en écrire une nouvelle qui prend GUIWriter en tant que paramètre. Si je commençais par définir une interface IWriter et que la méthode prenne un IWriter, je pourrais commencer par ConsoleWriter (qui implémenterait l'interface IWriter), puis écrire une nouvelle classe appelée GUIWriter (qui implémente également l'interface IWriter), puis I aurait juste à changer la classe en cours de passage.
Une autre chose (ce qui est vrai pour C #, pas sûr de Java) est que vous ne pouvez étendre qu'une classe mais implémenter de nombreuses interfaces. Disons que j'ai eu des cours nommés Teacher, MathTeacher et HistoryTeacher. Maintenant, MathTeacher et HistoryTeacher s’étendent de Teacher, mais que se passe-t-il si nous voulons un cours qui représente à la fois un MathTeacher et un HistoryTeacher. Cela peut devenir assez compliqué d'essayer d'hériter de plusieurs classes alors que vous ne pouvez le faire que l'un après l'autre (il y a moyen, mais ils ne sont pas exactement optimaux). Avec les interfaces, vous pouvez avoir 2 interfaces appelées IMathTeacher et IHistoryTeacher, puis une classe qui s'étend de Teacher et implémente ces 2 interfaces.
L’inconvénient de l’utilisation des interfaces est que parfois je vois des personnes dupliquer du code (puisque vous devez créer l’implémentation pour chaque classe, l’implémentation de l’interface), mais il existe une solution propre à ce problème, par exemple l’utilisation de choses comme les délégués quel est l'équivalent Java de cela).
La principale raison d'utiliser les interfaces sur l'héritage est le découplage du code d'implémentation, mais ne pensez pas que l'héritage est mauvais, car il est toujours très utile.