---
title: "Substituir Condicional por Polimorfismo"
type: "refactoring-technique"
slug: "replace-conditional-with-polymorphism"
url: "http://localhost:3000/pt-br/replace-conditional-with-polymorphism.md"
category: "Simplifying Conditional Expressions"
description: "Problema: Você tem um condicional que executa várias ações dependendo do tipo ou das propriedades de um objeto. Solução: Crie subclasses correspondentes aos ramos do condicional. Nelas, crie um método compartilhado e mova para ele o código do ramo correspondente do condicional. Em seguida, substitua o condicional pela chamada do método relevante. O resultado é que a implementação adequada será obtida por meio de polimorfismo, dependendo da classe do objeto."
languages: ["java", "csharp", "php", "python", "typescript"]
---
# Substituir Condicional por Polimorfismo

> Problema: Você tem um condicional que executa várias ações dependendo do tipo ou das propriedades de um objeto. Solução: Crie subclasses correspondentes aos ramos do condicional. Nelas, crie um método compartilhado e mova para ele o código do ramo correspondente do condicional. Em seguida, substitua o condicional pela chamada do método relevante. O resultado é que a implementação adequada será obtida por meio de polimorfismo, dependendo da classe do objeto.

## Problem

Você tem um condicional que executa várias ações dependendo do tipo ou das propriedades de um objeto.

## Solution

Crie subclasses correspondentes aos ramos do condicional. Nelas, crie um método compartilhado e mova para ele o código do ramo correspondente do condicional. Em seguida, substitua o condicional pela chamada do método relevante. O resultado é que a implementação adequada será obtida por meio de polimorfismo, dependendo da classe do objeto.

## Why Refactor

Esta técnica de refatoração pode ajudar se seu código contém operadores que executam várias tarefas que variam com base em:

* Classe do objeto ou interface que ele implementa
* Valor de um campo do objeto
* Resultado da chamada de um dos métodos do objeto

Se uma nova propriedade ou tipo de objeto aparecer, você precisará procurar e adicionar código em todos os condicionais semelhantes. Assim, o benefício desta técnica é multiplicado se houver vários condicionais espalhados por todos os métodos de um objeto.

## Benefits

* Esta técnica adere ao princípio _Tell-Don’t-Ask_: em vez de perguntar a um objeto sobre seu estado e então executar ações com base nisso, é muito mais fácil simplesmente dizer ao objeto o que ele precisa fazer e deixar que ele mesmo decida como fazê-lo.
* Remove código duplicado. Você se livra de muitos condicionais quase idênticos.
* Se você precisar adicionar uma nova variante de execução, basta adicionar uma nova subclasse sem tocar no código existente (_Princípio Aberto/Fechado_).

## How to Refactor

#### Preparando-se para Refatorar

Para esta técnica de refatoração, você deve ter uma hierarquia de classes pronta que conterá comportamentos alternativos. Se você não tiver uma hierarquia como essa, crie uma. Outras técnicas ajudarão a tornar isso possível:

* [Substituir Código de Tipo por Subclasses](/pt-br/replace-type-code-with-subclasses). Serão criadas subclasses para todos os valores de uma determinada propriedade do objeto. Essa abordagem é simples, mas menos flexível, já que você não pode criar subclasses para as outras propriedades do objeto.
* [Substituir Código de Tipo por State/Strategy](/pt-br/replace-type-code-with-state-strategy). Uma classe será dedicada a uma determinada propriedade do objeto, e a partir dela serão criadas subclasses para cada valor da propriedade. A classe atual conterá referências aos objetos desse tipo e delegará a execução a eles.

Os passos a seguir pressupõem que você já criou a hierarquia.

#### Passos da Refatoração

1. Se o condicional estiver em um método que também executa outras ações, aplique [Extrair Método](/pt-br/extract-method).
2. Para cada subclasse da hierarquia, redefina o método que contém o condicional e copie o código do ramo correspondente do condicional para esse local.
3. Exclua esse ramo do condicional.
4. Repita a substituição até que o condicional fique vazio. Em seguida, exclua o condicional e declare o método como abstrato.
## Relations

**Eliminates smells**

- [Comandos Switch](/pt-br/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);
  }
}

// Em algum lugar do 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);
  }
}

// Em algum lugar do 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);
  }
}

// Em algum lugar do 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)

# Em algum lugar do 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);
  }
}

// Em algum lugar do código cliente
let speed = bird.getSpeed();
```

