---
title: "Remplacer le conditionnel par du polymorphisme"
type: "refactoring-technique"
slug: "replace-conditional-with-polymorphism"
url: "http://localhost:3000/fr/replace-conditional-with-polymorphism.md"
category: "Simplifying Conditional Expressions"
description: "Problème : vous avez une instruction conditionnelle qui exécute diverses actions selon le type ou les propriétés d’un objet. Solution : créez des sous-classes correspondant aux branches de la conditionnelle. Dans chacune, créez une méthode commune et déplacez-y le code de la branche correspondante de la conditionnelle. Remplacez ensuite la conditionnelle par l’appel de la méthode appropriée. Le résultat est que la bonne implémentation sera obtenue par polymorphisme en fonction de la classe de l’objet."
languages: ["java", "csharp", "php", "python", "typescript"]
---
# Remplacer le conditionnel par du polymorphisme

> Problème : vous avez une instruction conditionnelle qui exécute diverses actions selon le type ou les propriétés d’un objet. Solution : créez des sous-classes correspondant aux branches de la conditionnelle. Dans chacune, créez une méthode commune et déplacez-y le code de la branche correspondante de la conditionnelle. Remplacez ensuite la conditionnelle par l’appel de la méthode appropriée. Le résultat est que la bonne implémentation sera obtenue par polymorphisme en fonction de la classe de l’objet.

## Problem

Vous avez une instruction conditionnelle qui exécute diverses actions selon le type ou les propriétés d’un objet.

## Solution

Créez des sous-classes correspondant aux branches de la conditionnelle. Dans chacune, créez une méthode commune et déplacez-y le code de la branche correspondante de la conditionnelle. Remplacez ensuite la conditionnelle par l’appel de la méthode appropriée. Le résultat est que la bonne implémentation sera obtenue par polymorphisme en fonction de la classe de l’objet.

## Why Refactor

Cette technique de refactoring peut vous aider si votre code contient des opérateurs effectuant diverses tâches qui varient en fonction :

* de la classe de l’objet ou de l’interface qu’il implémente
* de la valeur d’un champ de l’objet
* du résultat de l’appel de l’une des méthodes de l’objet

Si une nouvelle propriété ou un nouveau type d’objet apparaît, vous devrez rechercher et ajouter du code dans toutes les conditionnelles similaires. Le bénéfice de cette technique est donc multiplié s’il existe plusieurs conditionnelles disséminées dans toutes les méthodes d’un objet.

## Benefits

* Cette technique respecte le principe _Tell-Don’t-Ask_ : au lieu d’interroger un objet sur son état puis d’exécuter des actions en conséquence, il est bien plus simple de dire à l’objet ce qu’il doit faire et de le laisser décider lui-même comment le faire.
* Supprime le code dupliqué. Vous vous débarrassez de nombreuses conditionnelles presque identiques.
* Si vous devez ajouter une nouvelle variante d’exécution, il vous suffit d’ajouter une nouvelle sous-classe sans toucher au code existant (_principe ouvert/fermé_).

## How to Refactor

#### Préparation au refactoring

Pour cette technique de refactoring, vous devez disposer d’une hiérarchie de classes déjà prête qui contiendra les comportements alternatifs. Si vous n’avez pas de hiérarchie de ce genre, créez-en une. D’autres techniques vous aideront à y parvenir :

* [Remplacer le code de type par des sous-classes](/fr/replace-type-code-with-subclasses). Des sous-classes seront créées pour toutes les valeurs d’une propriété particulière de l’objet. Cette approche est simple mais moins souple, car vous ne pouvez pas créer de sous-classes pour les autres propriétés de l’objet.
* [Remplacer le code de type par État/Stratégie](/fr/replace-type-code-with-state-strategy). Une classe sera dédiée à une propriété particulière de l’objet et des sous-classes en seront dérivées pour chaque valeur de la propriété. La classe actuelle contiendra des références aux objets de ce type et leur déléguera l’exécution.

Les étapes suivantes supposent que vous avez déjà créé la hiérarchie.

#### Étapes du refactoring

1. Si la conditionnelle se trouve dans une méthode qui exécute également d’autres actions, appliquez [Extraire la méthode](/fr/extract-method).
2. Pour chaque sous-classe de la hiérarchie, redéfinissez la méthode qui contient la conditionnelle et copiez-y le code de la branche conditionnelle correspondante.
3. Supprimez cette branche de la conditionnelle.
4. Répétez le remplacement jusqu’à ce que la conditionnelle soit vide. Supprimez ensuite la conditionnelle et déclarez la méthode abstraite.
## Relations

**Eliminates smells**

- [Instructions switch](/fr/smells/switch-statements.md)

## Code Examples

### java

```java
// Before
class Bird {
  // ...
  double getSpeed() {
    switch (type) {
      case EUROPEAN:
        return getBaseSpeed();
      case AFRICAN:
        return getBaseSpeed() - getLoadFactor() * numberOfCoconuts;
      case NORWEGIAN_BLUE:
        return (isNailed) ? 0 : getBaseSpeed(voltage);
    }
    throw new RuntimeException("Should be unreachable");
  }
}

// After
abstract class Bird {
  // ...
  abstract double getSpeed();
}

class European extends Bird {
  double getSpeed() {
    return getBaseSpeed();
  }
}
class African extends Bird {
  double getSpeed() {
    return getBaseSpeed() - getLoadFactor() * numberOfCoconuts;
  }
}
class NorwegianBlue extends Bird {
  double getSpeed() {
    return (isNailed) ? 0 : getBaseSpeed(voltage);
  }
}

// Quelque part dans le code client
speed = bird.getSpeed();
```

### csharp

```csharp
// Before
public class Bird 
{
  // ...
  public double GetSpeed() 
  {
    switch (type) 
    {
      case EUROPEAN:
        return GetBaseSpeed();
      case AFRICAN:
        return GetBaseSpeed() - GetLoadFactor() * numberOfCoconuts;
      case NORWEGIAN_BLUE:
        return isNailed ? 0 : GetBaseSpeed(voltage);
      default:
        throw new Exception("Should be unreachable");
    }
  }
}

// After
public abstract class Bird 
{
  // ...
  public abstract double GetSpeed();
}

class European: Bird 
{
  public override double GetSpeed() 
  {
    return GetBaseSpeed();
  }
}
class African: Bird 
{
  public override double GetSpeed() 
  {
    return GetBaseSpeed() - GetLoadFactor() * numberOfCoconuts;
  }
}
class NorwegianBlue: Bird
{
  public override double GetSpeed() 
  {
    return isNailed ? 0 : GetBaseSpeed(voltage);
  }
}

// Quelque part dans le code client
speed = bird.GetSpeed();
```

### php

```php
// Before
class Bird {
  // ...
  public function getSpeed() {
    switch ($this->type) {
      case EUROPEAN:
        return $this->getBaseSpeed();
      case AFRICAN:
        return $this->getBaseSpeed() - $this->getLoadFactor() * $this->numberOfCoconuts;
      case NORWEGIAN_BLUE:
        return ($this->isNailed) ? 0 : $this->getBaseSpeed($this->voltage);
    }
    throw new Exception("Should be unreachable");
  }
  // ...
}

// After
abstract class Bird {
  // ...
  abstract function getSpeed();
  // ...
}

class European extends Bird {
  public function getSpeed() {
    return $this->getBaseSpeed();
  }
}
class African extends Bird {
  public function getSpeed() {
    return $this->getBaseSpeed() - $this->getLoadFactor() * $this->numberOfCoconuts;
  }
}
class NorwegianBlue extends Bird {
  public function getSpeed() {
    return ($this->isNailed) ? 0 : $this->getBaseSpeed($this->voltage);
  }
}

// Quelque part dans le code client.
$speed = $bird->getSpeed();
```

### python

```python
// Before
class Bird:
    # ...
    def getSpeed(self):
        if self.type == EUROPEAN:
            return self.getBaseSpeed()
        elif self.type == AFRICAN:
            return self.getBaseSpeed() - self.getLoadFactor() * self.numberOfCoconuts
        elif self.type == NORWEGIAN_BLUE:
            return 0 if self.isNailed else self.getBaseSpeed(self.voltage)
        else:
            raise Exception("Should be unreachable")

// After
class Bird:
    # ...
    def getSpeed(self):
        pass

class European(Bird):
    def getSpeed(self):
        return self.getBaseSpeed()
    
    
class African(Bird):
    def getSpeed(self):
        return self.getBaseSpeed() - self.getLoadFactor() * self.numberOfCoconuts


class NorwegianBlue(Bird):
    def getSpeed(self):
        return 0 if self.isNailed else self.getBaseSpeed(self.voltage)

# Quelque part dans le code client
speed = bird.getSpeed()
```

### typescript

```typescript
// Before
class Bird {
  // ...
  getSpeed(): number {
    switch (type) {
      case EUROPEAN:
        return getBaseSpeed();
      case AFRICAN:
        return getBaseSpeed() - getLoadFactor() * numberOfCoconuts;
      case NORWEGIAN_BLUE:
        return (isNailed) ? 0 : getBaseSpeed(voltage);
    }
    throw new Error("Should be unreachable");
  }
}

// After
abstract class Bird {
  // ...
  abstract getSpeed(): number;
}

class European extends Bird {
  getSpeed(): number {
    return getBaseSpeed();
  }
}
class African extends Bird {
  getSpeed(): number {
    return getBaseSpeed() - getLoadFactor() * numberOfCoconuts;
  }
}
class NorwegianBlue extends Bird {
  getSpeed(): number {
    return (isNailed) ? 0 : getBaseSpeed(voltage);
  }
}

// Quelque part dans le code client
let speed = bird.getSpeed();
```

