Skip to content

Commit e5976c0

Browse files
committed
Enhance documentation on inheritance and interfaces in Java, adding definitions, analogies, and clarifying concepts for better understanding.
1 parent d1649ec commit e5976c0

2 files changed

Lines changed: 95 additions & 23 deletions

File tree

docs/cours/java/14-heritage.md

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
# Héritage
22

3-
L’héritage est un des piliers de la programmation orientée objet. Il permet de créer de nouvelles classes à partir de classes existantes, en réutilisant et en spécialisant leur comportement. Cela favorise la factorisation du code et la création de hiérarchies logiques.
3+
L’héritage est l’un des concepts fondamentaux de la programmation orientée objet (POO), au même titre que l’encapsulation et le polymorphisme. Il permet de créer de nouvelles classes à partir de classes existantes, en réutilisant et en spécialisant leur comportement. Grâce à l’héritage, on peut factoriser le code commun à plusieurs classes et organiser les concepts de manière hiérarchique, ce qui favorise la lisibilité, la maintenance et l’évolution des programmes.
44

5-
> **À retenir** : Grâce à l’héritage, une classe « enfant » hérite des attributs et méthodes de sa classe « parent », et peut en ajouter ou en modifier.
5+
> **Définition** : L’héritage consiste à définir une nouvelle classe (dite « classe dérivée » ou « classe enfant ») à partir d’une classe existante (dite « classe de base » ou « classe parente »). La classe enfant hérite des attributs et des méthodes de la classe parente, et peut en ajouter ou en modifier.
6+
7+
## Pourquoi utiliser l’héritage ?
8+
9+
- **Réutilisation du code** : Éviter de réécrire plusieurs fois le même code dans différentes classes.
10+
- **Organisation logique** : Structurer les concepts selon des relations « est-un » (ex : un Chien est un Animal).
11+
- **Extensibilité** : Ajouter facilement de nouveaux comportements spécifiques sans toucher au code existant.
12+
13+
> **Exemple d’analogie** : Dans la vie courante, on peut dire qu’un vélo, une voiture et un camion sont tous des véhicules. Ils partagent des caractéristiques communes (roues, moteur, capacité à se déplacer), mais chacun a aussi ses particularités. En POO, on modélisera cela par une classe `Vehicule` dont hériteront les classes `Velo`, `Voiture`, `Camion`.
14+
15+
---
616

717
## Mot-clef `extends`
818

9-
Pour hériter d’une classe en Java, on utilise le mot-clé `extends`.
19+
Pour hériter d’une classe en Java, on utilise le mot-clé `extends`. Cela signifie littéralement « étendre » la classe de base, c’est-à-dire en reprendre les caractéristiques tout en les complétant ou en les spécialisant.
1020

1121
```java
1222
class Personne {
@@ -34,11 +44,15 @@ class Enfant extends Personne {
3444
}
3545
```
3646

37-
> **Info** : Le mot-clé `super` permet d’appeler le constructeur ou les méthodes de la classe parente.
47+
Dans cet exemple, les classes `Adulte` et `Enfant` héritent de la classe `Personne`. Elles récupèrent automatiquement les attributs `nom` et `prenom`, ainsi que les méthodes publiques de `Personne`. Elles peuvent aussi ajouter leurs propres attributs ou redéfinir des méthodes si besoin.
48+
49+
> **Info** : Le mot-clé `super` permet d’appeler le constructeur ou les méthodes de la classe parente. C’est utile pour initialiser les attributs hérités ou réutiliser du code parent.
50+
51+
---
3852

3953
## Polymorphisme de méthodes
4054

41-
Le polymorphisme permet d’utiliser un objet enfant comme s’il était de type parent. Cela autorise l’utilisation de méthodes de la classe parente, mais ces méthodes peuvent être redéfinies (surchargées) dans la classe enfant.
55+
Le polymorphisme est la capacité d’un même nom de méthode à se comporter différemment selon l’objet qui la porte. Grâce à l’héritage, on peut utiliser un objet enfant comme s’il était de type parent. Cela autorise l’utilisation de méthodes de la classe parente, mais ces méthodes peuvent être redéfinies (on parle alors de « surcharge » ou plutôt de « redéfinition », en anglais *override*) dans la classe enfant.
4256

4357
```java
4458
class Point {
@@ -95,36 +109,49 @@ public class Program {
95109
}
96110
```
97111

98-
> **À savoir** : Le mot-clé `@Override` indique que la méthode redéfinit une méthode de la classe parente. Cela permet d’éviter les erreurs de signature.
112+
Dans ce code, la méthode `getNom()` est redéfinie dans chaque sous-classe. Lorsqu’on appelle `getHelloStr()` sur une variable de type `Forme`, c’est la version la plus spécialisée de `getNom()` qui est utilisée, selon le type réel de l’objet (ici, `Cercle` ou `Rectangle`).
113+
114+
> **À savoir** : Le mot-clé `@Override` indique que la méthode redéfinit une méthode de la classe parente. Cela permet d’éviter les erreurs de signature et améliore la lisibilité du code.
115+
116+
---
99117

100118
## Classes abstraites
101119

102-
Une classe abstraite est une classe que l’on ne peut pas instancier directement. Elle sert de modèle pour d’autres classes, qui devront en hériter et compléter les méthodes abstraites.
120+
Une classe abstraite est une classe que l’on ne peut pas instancier directement. Elle sert de modèle pour d’autres classes, qui devront en hériter et compléter les méthodes abstraites. C’est un outil puissant pour imposer une structure commune à plusieurs classes, tout en laissant la liberté de spécialiser certains comportements.
121+
122+
- Une classe abstraite peut contenir des attributs, des méthodes concrètes (avec code) et des méthodes abstraites (sans code, juste la signature).
123+
- On est donc obligé de créer une sous-classe qui en dérive et qui implémente les méthodes abstraites :
103124

104-
- Une classe abstraite peut contenir des attributs, des méthodes concrètes (avec code) et des méthodes abstraites (sans code).
105-
- On est donc obligé de créer une sous-classe qui en dérive :
125+
> **À noter** : Même si une classe abstraite ne peut pas être instanciée directement, elle peut parfaitement définir un ou plusieurs constructeurs. Ceux-ci servent à initialiser les attributs hérités par les sous-classes. Lorsqu’une sous-classe hérite d’une classe abstraite, elle peut (et doit souvent) appeler le constructeur de la classe abstraite via `super(...)` dans son propre constructeur. Cela permet de garantir que l’état de l’objet est correctement initialisé, même si l’on ne crée jamais d’instance directe de la classe abstraite.
106126
107127
```java
108128
abstract class Forme {
109129
protected Point centre;
110130
public Forme(Point c) {
111131
this.centre = c;
112132
}
133+
public abstract double getAire(); // Méthode abstraite
113134
}
114135
class Cercle extends Forme {
115136
protected double rayon;
116137
public Cercle(Point c, double rayon) {
117-
super(c);
138+
super(c); // Appel du constructeur de la classe abstraite
118139
this.rayon = rayon;
119140
}
141+
@Override
142+
public double getAire() {
143+
return Math.PI * rayon * rayon;
144+
}
120145
}
121146
// Dans le main :
122147
Cercle c = new Cercle(new Point(5, 6), 5.2); // OK
123148
Forme fc = new Cercle(new Point(5, 7), 3.0); // OK
124149
// Forme f = new Forme(new Point(0,0)); // Erreur : on ne peut pas instancier une classe abstraite
125150
```
126151

127-
> **Info** : Utilisez les classes abstraites pour définir des comportements communs à plusieurs classes, tout en forçant la spécialisation de certaines méthodes dans les sous-classes.
152+
> **Info** : Utilisez les classes abstraites pour définir des comportements communs à plusieurs classes, tout en forçant la spécialisation de certaines méthodes dans les sous-classes. Cela permet de garantir que toutes les sous-classes respecteront un contrat minimal.
153+
154+
---
128155

129156
## Le mot-clé `super` et la résolution statique
130157

@@ -156,9 +183,9 @@ public class Demo {
156183
}
157184
```
158185

186+
> **Astuce :** Utilisez `super` pour accéder à une méthode ou un constructeur parent, mais gardez en tête que le polymorphisme ne s'applique pas à `super`.
159187
160-
> **Astuce :**
161-
> Utilisez `super` pour accéder à une méthode ou un constructeur parent, mais gardez en tête que le polymorphisme ne s'applique pas à `super`.
188+
---
162189

163190
## Détail de l'exemple sur `super` et `this`
164191

@@ -205,14 +232,20 @@ Cet exemple est fondamental pour bien comprendre le comportement de l'héritage
205232

206233
---
207234

208-
L’héritage et le polymorphisme sont essentiels pour structurer des programmes évolutifs et réutilisables. N’hésitez pas à expérimenter avec vos propres hiérarchies de classes pour bien comprendre leur puissance et leurs subtilités !
209-
210-
---
211-
212235
## Encadré : SOLID et héritage
213236

214237
L’héritage est directement concerné par le principe de substitution de Liskov (**L** de SOLID) : toute classe dérivée doit pouvoir être utilisée à la place de sa classe parente sans altérer le bon fonctionnement du programme.
215238

216239
> **À retenir :** Respecter ce principe garantit la robustesse et la cohérence de vos hiérarchies de classes.
217240
218241
Pour une explication complète des principes SOLID, voir le chapitre dédié.
242+
243+
---
244+
245+
## Pour aller plus loin
246+
247+
- **Composition vs héritage** : L’héritage n’est pas la seule façon de réutiliser du code. Parfois, il est préférable d’utiliser la composition (une classe possède une autre classe) plutôt que l’héritage (une classe est une autre classe). On parle alors du principe « favor composition over inheritance ».
248+
- **Limites de l’héritage** : Un mauvais usage de l’héritage peut conduire à des hiérarchies trop rigides ou à des problèmes de maintenance. Il est important de bien réfléchir à la structure de ses classes.
249+
- **Interfaces** : En Java, une classe peut hériter d’une seule classe (héritage simple), mais peut implémenter plusieurs interfaces. Les interfaces permettent de définir des contrats que les classes doivent respecter, sans imposer d’implémentation.
250+
251+
N’hésitez pas à expérimenter avec vos propres hiérarchies de classes pour bien comprendre la puissance et les subtilités de l’héritage en Java !

docs/cours/java/15-interfaces.md

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,18 @@
22

33
Les interfaces sont un concept fondamental de la programmation orientée objet en Java. Elles permettent de définir des contrats que les classes doivent respecter, sans imposer d’implémentation concrète. Cela favorise la flexibilité, le découplage et la réutilisabilité du code.
44

5-
> **À retenir** : Une interface définit ce qu’une classe doit faire, mais pas comment elle doit le faire.
5+
> **Définition** : Une interface définit ce qu’une classe doit faire, mais pas comment elle doit le faire. Elle impose un contrat, c’est-à-dire un ensemble de méthodes que toute classe qui « implémente » l’interface doit obligatoirement fournir.
6+
7+
## Pourquoi utiliser les interfaces ?
8+
9+
- **Découplage** : Les interfaces permettent de séparer le « quoi » (le contrat) du « comment » (l’implémentation). Cela rend le code plus flexible et plus facile à faire évoluer.
10+
- **Polymorphisme** : On peut manipuler des objets de différentes classes via une même interface, ce qui permet d’écrire du code générique et réutilisable.
11+
- **Testabilité** : Les interfaces facilitent la création de fausses implémentations (mocks) pour les tests unitaires.
12+
- **Extensibilité** : On peut ajouter de nouvelles implémentations sans modifier le code existant.
13+
14+
> **Analogie** : Une interface, c’est comme un contrat de location : le propriétaire (l’interface) impose des règles (méthodes à implémenter), mais chaque locataire (classe concrète) peut meubler l’appartement à sa façon (implémentation différente).
15+
16+
---
617

718
## Qu'est-ce qu'une interface ?
819

@@ -25,7 +36,9 @@ public interface Perimetrable {
2536
}
2637
```
2738

28-
> **Info** : Par convention, le nom d’une interface commence par une majuscule.
39+
> **Info** : Par convention, le nom d’une interface commence par une majuscule. On utilise souvent un nom qui exprime une capacité ou un rôle (ex : `Serializable`, `Comparable`, `Runnable`).
40+
41+
---
2942

3043
## Utilisation d'une interface
3144

@@ -58,14 +71,16 @@ class Main {
5871
```
5972

6073
> **À savoir** : On peut caster une variable pour accéder à des méthodes spécifiques à la classe :
61-
>
6274
> ```java
6375
> System.out.println(((Carre)p).getCote()); // OK
6476
> ```
6577
78+
---
79+
6680
## Implémentation d'une interface
6781
68-
- Utilisation du mot-clef `implements` :
82+
- Utilisation du mot-clef `implements` : une classe peut implémenter une ou plusieurs interfaces, en séparant les noms par des virgules.
83+
- Une classe qui implémente une interface doit fournir une implémentation pour toutes les méthodes abstraites de l’interface.
6984
7085
```java
7186
class Forme implements Perimetrable {
@@ -85,6 +100,10 @@ class Rectangle extends Forme {
85100
}
86101
```
87102
103+
> **Remarque** : Une classe abstraite peut aussi implémenter une interface, mais elle n’est pas obligée d’implémenter toutes les méthodes de l’interface. Ce sera alors aux sous-classes concrètes de le faire.
104+
105+
---
106+
88107
## Implémentation de plusieurs interfaces
89108
90109
- Une classe peut implémenter plusieurs interfaces :
@@ -97,6 +116,8 @@ public class Forme implements Perimetrable, java.io.Serializable {
97116
98117
- Si deux interfaces héritées ont des méthodes de même signature, il suffit de l’implémenter une seule fois.
99118
119+
---
120+
100121
## Hiérarchie d'interfaces
101122
102123
- Une interface peut hériter d’une ou plusieurs autres interfaces :
@@ -112,14 +133,20 @@ interface ComplexPerimetrable extends Perimetrable {
112133
113134
- Une interface qui hérite d’une autre interface hérite de toutes ses méthodes.
114135

136+
> **Exemple** : L’interface `List` hérite de `Collection`, qui hérite de `Iterable`.
137+
138+
---
139+
115140
## Interfaces et UML
116141

117142
En UML, les interfaces sont représentées par le stéréotype `<<interface>>` ou par une classe avec une petite flèche en pointillés.
118143

119-
![Implémentation d'interface en UML](https://i.stack.imgur.com/ztO39.png)
144+
![Implémentation d'interface en UML]()
120145

121146
La flèche en pointillés va de la classe concrète vers l’interface.
122147

148+
---
149+
123150
## Méthodes par défaut
124151

125152
- Depuis Java 8, une interface peut contenir des méthodes avec une implémentation par défaut :
@@ -132,7 +159,9 @@ interface MonInterface {
132159
}
133160
```
134161

135-
> **Info** : Les méthodes par défaut sont utiles pour faire évoluer une interface sans forcer toutes les classes à réécrire du code.
162+
> **Info** : Les méthodes par défaut sont utiles pour faire évoluer une interface sans forcer toutes les classes à réécrire du code. Cela permet d’ajouter de nouvelles fonctionnalités tout en maintenant la compatibilité avec les anciennes implémentations.
163+
164+
---
136165

137166
## Découplage grâce aux interfaces
138167

@@ -302,3 +331,13 @@ Les interfaces jouent un rôle clé dans deux principes SOLID :
302331
> **À retenir :** Les interfaces permettent d’appliquer ces principes pour rendre le code plus flexible, modulaire et testable.
303332
304333
Pour une explication complète des principes SOLID, voir le chapitre dédié.
334+
335+
---
336+
337+
## Pour aller plus loin
338+
339+
- **Interfaces vs classes abstraites** : Les interfaces définissent uniquement un contrat, tandis que les classes abstraites peuvent fournir une implémentation partielle. Une classe peut implémenter plusieurs interfaces, mais n’hériter que d’une seule classe abstraite.
340+
- **Interfaces fonctionnelles** : Utilisées pour la programmation fonctionnelle et les expressions lambda (voir chapitre 19).
341+
- **API Java** : De nombreuses API Java reposent sur les interfaces (`List`, `Map`, `Runnable`, etc.).
342+
343+
N’hésitez pas à expérimenter avec vos propres interfaces pour bien comprendre leur utilité et leur puissance en Java !

0 commit comments

Comments
 (0)