---
title: "Reemplazar condicional con polimorfismo"
type: "refactoring-technique"
slug: "replace-conditional-with-polymorphism"
url: "http://localhost:3000/es/replace-conditional-with-polymorphism.md"
category: "Simplifying Conditional Expressions"
description: "Problema: Tienes un condicional que ejecuta diversas acciones en función del tipo o las propiedades de un objeto. Solución: Crea subclases que se correspondan con las ramas del condicional. En ellas, crea un método compartido y traslada a él el código de la rama correspondiente del condicional. Después, reemplaza el condicional por la llamada al método pertinente. El resultado es que se alcanzará la implementación adecuada mediante polimorfismo en función de la clase del objeto."
languages: ["java", "csharp", "php", "python", "typescript"]
---
# Reemplazar condicional con polimorfismo

> Problema: Tienes un condicional que ejecuta diversas acciones en función del tipo o las propiedades de un objeto. Solución: Crea subclases que se correspondan con las ramas del condicional. En ellas, crea un método compartido y traslada a él el código de la rama correspondiente del condicional. Después, reemplaza el condicional por la llamada al método pertinente. El resultado es que se alcanzará la implementación adecuada mediante polimorfismo en función de la clase del objeto.

## Problem

Tienes un condicional que ejecuta diversas acciones en función del tipo o las propiedades de un objeto.

## Solution

Crea subclases que se correspondan con las ramas del condicional. En ellas, crea un método compartido y traslada a él el código de la rama correspondiente del condicional. Después, reemplaza el condicional por la llamada al método pertinente. El resultado es que se alcanzará la implementación adecuada mediante polimorfismo en función de la clase del objeto.

## Why Refactor

Esta técnica de refactorización puede ayudar si tu código contiene operadores que ejecutan diversas tareas que varían en función de:

* La clase del objeto o la interfaz que implementa
* El valor de un campo de un objeto
* El resultado de llamar a uno de los métodos de un objeto

Si aparece una nueva propiedad o tipo de objeto, tendrás que buscar y añadir código en todos los condicionales similares. Por tanto, el beneficio de esta técnica se multiplica si hay múltiples condicionales repartidos por todos los métodos de un objeto.

## Benefits

* Esta técnica respeta el principio _Tell-Don’t-Ask_ (di, no preguntes): en lugar de preguntar a un objeto por su estado y luego ejecutar acciones en función de ello, es mucho más fácil simplemente decirle al objeto qué tiene que hacer y dejar que decida por sí mismo cómo hacerlo.
* Elimina código duplicado. Te deshaces de muchos condicionales casi idénticos.
* Si necesitas añadir una nueva variante de ejecución, lo único que tienes que hacer es añadir una nueva subclase sin tocar el código existente (_principio abierto/cerrado_).

## How to Refactor

#### Preparación para la refactorización

Para esta técnica de refactorización deberías tener lista una jerarquía de clases que contenga los comportamientos alternativos. Si no tienes una jerarquía así, créala. Otras técnicas te ayudarán a conseguirlo:

* [Reemplazar código de tipo con subclases](/es/replace-type-code-with-subclasses). Se crearán subclases para todos los valores de una determinada propiedad del objeto. Este enfoque es sencillo, pero menos flexible, ya que no puedes crear subclases para las demás propiedades del objeto.
* [Reemplazar código de tipo con estado/estrategia](/es/replace-type-code-with-state-strategy). Se dedicará una clase a una determinada propiedad del objeto y se crearán subclases a partir de ella para cada valor de la propiedad. La clase actual contendrá referencias a los objetos de este tipo y les delegará la ejecución.

Los pasos siguientes asumen que ya has creado la jerarquía.

#### Pasos de la refactorización

1. Si el condicional está en un método que también ejecuta otras acciones, aplica [Extraer método](/es/extract-method).
2. Para cada subclase de la jerarquía, redefine el método que contiene el condicional y copia en esa ubicación el código de la rama correspondiente del condicional.
3. Elimina esta rama del condicional.
4. Repite el reemplazo hasta que el condicional quede vacío. Después, elimina el condicional y declara el método como abstracto.
## Relations

**Eliminates smells**

- [Sentencias switch](/es/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);
  }
}

// En algún lugar del código cliente
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);
  }
}

// En algún lugar del código cliente
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);
  }
}

// En algún lugar del código cliente.
$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)

# En algún lugar del código cliente
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);
  }
}

// En algún lugar del código cliente
let speed = bird.getSpeed();
```

