Section courante

A propos

Section administrative du site

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 :

Polymorphisme et relation IS-A

Le polymorphisme repose sur une relation IS-A, obtenue via :

Exemple :

Types de polymorphisme

Polymorphisme statique (compilation)

Aussi appelé surcharge, il est résolu à la compilation.

  1. class Calculatrice {
  2.     int addition(int a, int b) {
  3.         return a + b;
  4.     }
  5.  
  6.     double addition(double a, double b) {
  7.         return a + b;
  8.     }
  9. }

ou en langage de programmation Free Pascal :

  1. Program ExempleCalculatrice;
  2.  
  3. {$mode objfpc}  { Active le mode objet compatible Delphi }
  4.  
  5. Type
  6.  TCalculatrice=Class
  7.   Public
  8.    Function Addition(a,b:Integer):Integer; overload;
  9.    Function Addition(a,b:Double):Double; overload;
  10.  End;
  11.  
  12.  { Implémentation des méthodes }
  13. Function TCalculatrice.Addition(a,b:Integer):Integer;Begin
  14.  Result:=a + b;
  15. End;
  16.  
  17. Function TCalculatrice.Addition(a,b:Double):Double;Begin
  18.  Result:=a + b;
  19. End;
  20.  
  21.  { Programme principal }
  22. Var
  23.  Calc:TCalculatrice;
  24.  iRes:Integer;
  25.  dRes:Double;
  26. BEGIN
  27.  Calc:=TCalculatrice.Create;
  28.  Try
  29.   iRes:=Calc.Addition(5, 3);       { Appel avec entiers }
  30.   dRes:=Calc.Addition(2.5, 4.7);   { Appel avec réels }
  31.   WriteLn('Addition entiers : ', iRes);
  32.   WriteLn('Addition réels : ', dRes:0:2);
  33.  Finally
  34.   Calc.Free;
  35.  End;
  36. 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.

  1. Animal a = new Chien();
  2. a.crier();  // appelle la version Chien

C'est le polymorphisme central en POO.

Polymorphisme par héritage

Classe parente

  1. abstract class Animal {
  2.     public abstract void crier();
  3. }

Classes filles

  1. class Chien extends Animal {
  2.     @Override
  3.     public void crier() {
  4.         System.out.println("Le chien aboie");
  5.     }
  6. }
  7.  
  8. class Chat extends Animal {
  9.     @Override
  10.     public void crier() {
  11.         System.out.println("Le chat miaule");
  12.     }
  13. }

Utilisation polymorphe

  1. List<Animal> animaux = List.of(
  2.     new Chien(),
  3.     new Chat()
  4. );
  5.  
  6. for (Animal a : animaux) {
  7.     a.crier();
  8. }

Le type réel de l'objet détermine le comportement exécuté.

Polymorphisme par interface

Interface

  1. interface MoyenPaiement {
  2.     void payer(double montant);
  3. }

Implémentations

  1. class CarteBancaire implements MoyenPaiement {
  2.     public void payer(double montant) {
  3.         System.out.println("Paiement par carte");
  4.     }
  5. }
  6.  
  7. class Paypal implements MoyenPaiement {
  8.     public void payer(double montant) {
  9.         System.out.println("Paiement via Paypal");
  10.     }
  11. }

Code client polymorphe

  1. void effectuerPaiement(MoyenPaiement moyen) {
  2.     moyen.payer(100);
  3. }

Liaison dynamique (Dynamic Binding)

Le polymorphisme dynamique repose sur la liaison tardive :

Exemple :

  1. Animal a = new 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 :

  1. class Rectangle {
  2.     int largeur, hauteur;
  3.     void setLargeur(int l) { largeur = l; }
  4.     void setHauteur(int h) { hauteur = h; }
  5. }
  6.  
  7. class Carre extends Rectangle {
  8.     void setLargeur(int l) {
  9.         largeur = hauteur = l;
  10.     }
  11. }

Le polymorphisme devient dangereux si les contrats ne sont pas respectés.

Polymorphisme vs conditions

Mauvaise approche :

  1. if (animal instanceof Chien) { ... }
  2. else if (animal instanceof Chat) { ... }

Bonne approche :

  1. animal.crier();

Le polymorphisme remplace les tests de type.

Polymorphisme et abstraction

Le polymorphisme s'appuie sur l'abstraction :

Sans abstraction, le polymorphisme est limité et fragile.

Cas réel : moteur de rendu graphique

  1. interface Forme {
  2.     void dessiner();
  3. }
  4.  
  5. class Cercle implements Forme {
  6.     public void dessiner() {
  7.         System.out.println("Dessiner un cercle");
  8.     }
  9. }
  10.  
  11. class Rectangle implements Forme {
  12.     public void dessiner() {
  13.         System.out.println("Dessiner un rectangle");
  14.     }
  15. }
  16.  
  17. void render(List<Forme> formes) {
  18.     for (Forme f : formes) {
  19.         f.dessiner();
  20.     }
  21. }

Polymorphisme et performances

Bonnes pratiques

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 :

  1. #include <iostream>
  2.  
  3. class maclasse {
  4.   public:
  5.    virtual int Type() = 0;
  6. };
  7.  
  8. class biologie:public maclasse {
  9.  public:
  10.   virtual int Type() { return 1; }
  11. };
  12.  
  13. class informatique:public maclasse {
  14.  public:
  15.   virtual int Type() { return 2; }
  16. };
  17.  
  18. int main(void) {
  19.   biologie A;
  20.   informatique B;
  21.   std::cout << "Type A: " << A.Type() << std::endl;
  22.   std::cout << "Type B: " << B.Type() << std::endl;
  23.   return 0;
  24. }

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.



Dernière mise à jour : Mardi, le 1 novembre 2016