« Bonjour, Amigo ! Je vais te parler d'un sujet que tu vas, je crois, utiliser souvent. Je parle là de l'héritage. »

Pour les non-initiés, la programmation est comme la magie. Alors permets-moi de commencer par une analogie…

Supposons que tu es un magicien qui veut créer un cheval volant. Tu pourrais essayer d'invoquer un Pegasus. Mais comme les chevaux volants ne sont pas d'origine naturelle, tu risques d'avoir du mal. Tu vas avoir beaucoup de travail à faire. Ce serait bien plus simple de commencer par un cheval et de lui coller des ailes.

Héritage. Les avantages de l'héritage - 1

En programmation, nous appelons ce processus 'héritage'. Supposons que tu as besoin d'écrire une classe très complexe. Tu pourrais passer des heures à écrire du code à partir de rien, puis effectuer de longs tests pour trouver des bogues. Mais pourquoi se compliquer la vie ? Ce ne serait pas mieux de chercher à savoir si la classe que tu veux créer existe déjà ?

Disons que tu trouves une classe qui implémente 80 % des fonctionnalités dont tu as besoin. Tu peux simplement copier son code dans ta classe. Mais cela présenterait plusieurs inconvénients :

1) La classe que tu trouveras a peut-être déjà été compilée en bytecode. Tu n'auras pas forcément accès à son code source.

2) Tu as peut-être le code source de la classe, mais tu travailles dans une entreprise qui pourrait être poursuivie pour des milliards si tu utilisais ne serait-ce que 6 lignes du code de quelqu'un d'autre. Bonjour les procès.

3) Cela conduit à la duplication inutile de tonnes de code. Et si l'auteur de l'autre classe trouve un bogue et le corrige, toi tu l'auras toujours.

Il existe une façon plus élégante qui ne nécessite pas d'obtenir d'autorisation légale pour le code de la classe d'origine. En Java, tu peux simplement déclarer l'autre classe comme le parent de ta classe. Cela équivaut à ajouter le code de cette classe à ta propre classe. Toutes les données et méthodes de la classe parente apparaîtront dans ta classe. Par exemple, tu peux hériter d'un 'cheval', lui ajouter des 'ailes' et obtenir un 'Pegasus'.

Héritage. Les avantages de l'héritage - 2

« Très intéressant. Continue, s'il te plaît. »

« L'héritage a d'autres usages. Supposons que tu as dix classes qui sont très similaires. Elles ont des données et des méthodes équivalentes. Tu pourrais créer une classe de base spéciale, déplacer les données communes (et méthodes associées) dans la classe de base et en faire hériter tes dix classes. En d'autres termes, pour chaque classe, tu indiques qu'elle a une classe parente, également connue sous le nom de classe de base. »

« Tout comme les avantages de l'abstraction ne sont vraiment apparents que dans le cadre de l'encapsulation, les avantages de l'héritage sont amplifiés par le polymorphisme. Mais je te reparlerai de ça demain. Aujourd'hui, penchons-nous sur quelques exemples d'héritage. »

« Supposons que nous écrivons un programme d'échecs. Nous aurons besoin de classes pour les différents types de pions. Quelles classes proposerais-tu, Amigo ? »

« Roi, reine, fou, cavalier, tour et pion. »

« Très bien. Je vois que tu as suivi. »

« Et quelles données proposerais-tu de stocker dans ces classes ? »

« La position de chaque pion (x et y) et leur valeur. Après tout, certains pions sont plus utiles que d'autres. »

« Et quelles sont les différences entre ces classes ? »

« Les pions se déplacent de différentes façons. Leur comportement varie. »

« Oui. Tu peux les définir comme des classes de cette façon : »

class King
{
int x;
int y;
int worth;
void kingMove()
{
//code that defines,
//how the king moves
}
}
class Queen
{
int x;
int y;
int worth;
void queenMove()
{
//code that defines,
//how the queen moves
}
}
class Rook
{
int x;
int y;
int worth;
void rookMove()
{
//code that defines,
//how the rook moves
}
}
class Knight
{
int x;
int y;
int worth;
void knightMove()
{
//code that defines,
//how the knight moves
}
}
class Bishop
{
int x;
int y;
int worth;
void bishopMove()
{
//code that defines,
//how the bishop moves
}
}
class Pawn
{
int x;
int y;
int worth;
void pawnMove()
{
//code that defines,
//how the pawn moves
}
}

« Oui, c'est exactement comme ça que je l'écrirais. »

« Mais regarde comment tu peux utiliser l'héritage pour écrire moins de code. Nous pouvons déplacer les méthodes et données identiques dans une classe commune. Appelons-la ChessItem. Cela n'aurait pas de sens de créer des objets ChessItem, car ils ne correspondent pas à des pièces utilisables en échecs. Mais la classe serait extrêmement utile : »

class King extends ChessItem
{
void kingMove()
{
//code that defines,
//how the king moves
}
}
class Queen extends ChessItem
{
void queenMove()
{
//code that defines,
//how the queen moves
}
}
class Rook extends ChessItem
{
void rookMove()
{
//code that defines,
//how the rook moves
}
}
 class ChessItem
{
int x;
int y;
int worth;
}
 
class Knight extends ChessItem
{
void knightMove()
{
//code that defines,
//how the knight moves
}
}
class Bishop extends ChessItem
{
void bishopMove()
{
//code that defines,
//how the bishop moves
}
}
class Pawn extends ChessItem
{
void pawnMove()
{
//code that defines,
//how the pawn moves
}
}

« C'est super intéressant ! »

« Absolument ! L'avantage est particulièrement important dans les projets contenant des milliers d'objets différents et des centaines de classes. Dans ce cas, des classes bien choisies peuvent non seulement simplifier considérablement la logique, mais aussi réduire le code requis par un facteur de dix. »

« Alors, comment faire pour hériter d'une classe ? »

« Après avoir déclaré une classe, nous utilisons le mot-clé 'extends' suivi du nom de la classe parente. Tu peux hériter d'une seule classe. »

Héritage. Les avantages de l'héritage - 3

L'image montre une « vache » qui a hérité d'un « cochon ». Le « cochon » hérite de la « poule », et la « poule » hérite de l'« œuf ». Chaque classe a un seul parent ! Un tel héritage n'est pas toujours logique. Si tu as seulement un cochon mais que tu as vraiment besoin d'une vache, les programmeurs ont souvent du mal à résister au désir de créer une « vache » à partir du « cochon ».

« Mais si je veux hériter de deux classes ? Il n'y a pas quelque chose que je peux faire ? »

« Pas vraiment. Les classes Java ne prennent pas en charge l'héritage multiple de l'implémentation : une classe ne peut avoir qu'une seule classe parente. Mais il y a l'héritage multiple de type, ce qui signifie qu'une classe peut implémenter plus d'une interface. Cela atténue un peu le problème. »

« Je vois. Et c'est quoi, une interface ? »

« Je te parlerai des interfaces demain. Pour l'instant, continuons à nous plonger dans l'héritage. »