Polymorphisme
Le polymorphisme est l'un des quatre piliers fondamentaux de la programmation orientée objet, avec l'encapsulation, l'héritage et l'abstraction.
Le terme provient du grec poly (plusieurs) et morphê (formes) et signifie littéralement «plusieurs formes».
En POO, le polymorphisme désigne la capacité à manipuler des objets de types différents à travers une même interface, tout en déclenchant des comportements différents selon le type réel de l'objet.
Autrement dit :
une même instruction peut produire des effets différents selon l'objet concerné.
Pourquoi le polymorphisme est-il essentiel ?
Le polymorphisme apporte des bénéfices majeurs :
Flexibilité du code
Le code client n'a pas besoin de connaître le type concret des objets.
Extensibilité
De nouveaux comportements peuvent être ajoutés sans modifier le code existant.
Lisibilité et élégance
Les structures conditionnelles complexes (if, switch) sont remplacées par des appels polymorphes.
Respect des principes SOLID
Le polymorphisme est central dans :
- Open/Closed Principle
- Liskov Substitution Principle
Polymorphisme et relation IS-A
Le polymorphisme repose sur une relation IS-A, obtenue via :
- l'héritage
- les interfaces
Exemple :
- Un Chien est un Animal
- Un PaiementPaypal est un MoyenPaiement
Types de polymorphisme
Polymorphisme statique (compilation)
Aussi appelé surcharge, il est résolu à la compilation.
ou en langage de programmation Free Pascal :
- Program ExempleCalculatrice;
-
- {$mode objfpc} { Active le mode objet compatible Delphi }
-
- Type
- TCalculatrice=Class
- Public
- Function Addition(a,b:Integer):Integer; overload;
- Function Addition(a,b:Double):Double; overload;
- End;
-
- { Implémentation des méthodes }
- Function TCalculatrice.Addition(a,b:Integer):Integer;Begin
- Result:=a + b;
- End;
-
- Function TCalculatrice.Addition(a,b:Double):Double;Begin
- Result:=a + b;
- End;
-
- { Programme principal }
- Var
- Calc:TCalculatrice;
- iRes:Integer;
- dRes:Double;
- BEGIN
- Calc:=TCalculatrice.Create;
- Try
- iRes:=Calc.Addition(5, 3); { Appel avec entiers }
- dRes:=Calc.Addition(2.5, 4.7); { Appel avec réels }
- WriteLn('Addition entiers : ', iRes);
- WriteLn('Addition réels : ', dRes:0:2);
- Finally
- Calc.Free;
- End;
- END.
Le choix de la méthode dépend des paramètres, pas de l'objet.
Polymorphisme dynamique (exécution)
Aussi appelé redéfinition, il est résolu à l'exécution.
- Animal a = new Chien();
- a.crier(); // appelle la version Chien
C'est le polymorphisme central en POO.
Polymorphisme par héritage
Classe parente
Classes filles
Utilisation polymorphe
Le type réel de l'objet détermine le comportement exécuté.
Polymorphisme par interface
Interface
Implémentations
Code client polymorphe
- void effectuerPaiement(MoyenPaiement moyen) {
- moyen.payer(100);
- }
Liaison dynamique (Dynamic Binding)
Le polymorphisme dynamique repose sur la liaison tardive :
- Le type de la référence est connu à la compilation
- Le type réel de l'objet est déterminé à l'exécution
Exemple :
- Animal a = new Chien();
- Type statique : Animal
- Type dynamique : Chien
Le principe de substitution de Liskov (LSP)
Toute instance d'une classe dérivée doit pouvoir être utilisée à la place de sa classe de base sans altérer le comportement du programme.
Violation classique :
Le polymorphisme devient dangereux si les contrats ne sont pas respectés.
Polymorphisme vs conditions
Mauvaise approche :
Bonne approche :
- animal.crier();
Le polymorphisme remplace les tests de type.
Polymorphisme et abstraction
Le polymorphisme s'appuie sur l'abstraction :
- interfaces
- classes abstraites
Sans abstraction, le polymorphisme est limité et fragile.
Cas réel : moteur de rendu graphique
- interface Forme {
- void dessiner();
- }
-
- class Cercle implements Forme {
- public void dessiner() {
- System.out.println("Dessiner un cercle");
- }
- }
-
- class Rectangle implements Forme {
- public void dessiner() {
- System.out.println("Dessiner un rectangle");
- }
- }
-
- void render(List<Forme> formes) {
- for (Forme f : formes) {
- f.dessiner();
- }
- }
Polymorphisme et performances
- L'appel polymorphe a un coût minime
- Optimisé par les compilateurs modernes (JIT, VTable)
- Le gain en maintenabilité dépasse largement l'impact performance
Bonnes pratiques
- Programmer contre des abstractions
- Respecter Liskov
- Éviter les instanceof
- Utiliser des méthodes cohérentes
- Préférer la clarté à la complexité
Polymorphisme dans différents langages
| Langage | Support |
|---|---|
| C++ | Héritage + virtual |
| C# | Héritage + interfaces |
| Delphi | Héritage + méthodes virtual / override + interfaces |
| Free Pascal | Héritage + méthodes virtual / override + interfaces |
| Java | Héritage + interfaces |
| PHP | Héritage + interfaces |
| Python | Duck typing |
Exemple
En langage de programmation orienté objet (POO), on appel «Polymorphisme», la possibilité d'avoir un même types de données pour une même méthode dans différentes classes. Ainsi, on peut avoir le même nom de méthode et avoir des types de données identiques pour des traitements différents. Un exemple pratique du polymorphisme, serait une première méthode appeler pour de la chimie et la seconde pour biologie.
L'exemple suivant, écrit en langage de programmation C++, permet de montrer que la méthode «Type» est utilisé dans trois classes et qu'elle est hérité d'une première classe :
- #include <iostream>
-
- class maclasse {
- public:
- virtual int Type() = 0;
- };
-
- class biologie:public maclasse {
- public:
- virtual int Type() { return 1; }
- };
-
- class informatique:public maclasse {
- public:
- virtual int Type() { return 2; }
- };
-
- int main(void) {
- biologie A;
- informatique B;
- std::cout << "Type A: " << A.Type() << std::endl;
- std::cout << "Type B: " << B.Type() << std::endl;
- return 0;
- }
Conclusion
Le polymorphisme est le cour de la flexibilité en POO. Il permet d'écrire du code ouvert à l'extension, fermé à la modification, tout en restant lisible et robuste.