Logotipo do ConstructiCat
CodeBust.
Explorar a seção ▾

Substituir Código de Tipo por Estado/Estratégia.

Problema

Você tem um tipo codificado que afeta o comportamento, mas não pode usar subclasses para se livrar dele.

Solução

Substitua o código de tipo por um objeto de estado. Se for necessário substituir o valor de um campo por código de tipo, outro objeto de estado é “plugado”.

##Exemplo

Antes
class Employee {
  static final int ENGINEER = 0;
  static final int SALESMAN = 1;
  private int type;

  int payAmount() {
    switch (type) {
      case ENGINEER: return monthlySalary;
      case SALESMAN: return monthlySalary + commission;
      default: throw new IllegalStateException();
    }
  }
}
Depois
class Employee {
  private EmployeeType type;

  int payAmount() { return type.payAmount(this); }
  void setType(EmployeeType arg) { type = arg; }
}
abstract class EmployeeType {
  abstract int payAmount(Employee emp);
}
class Engineer extends EmployeeType {
  int payAmount(Employee emp) { return emp.monthlySalary; }
}
class Salesman extends EmployeeType {
  int payAmount(Employee emp) { return emp.monthlySalary + emp.commission; }
}

##Por que refatorar

Você tem um código de tipo e ele afeta o comportamento de uma classe, portanto não podemos usar Substituir Código de Tipo por Classe.

O código de tipo afeta o comportamento de uma classe, mas não podemos criar subclasses para o tipo codificado devido à hierarquia de classes existente ou a outros motivos. Isso significa que não podemos aplicar Substituir Código de Tipo por Subclasses.

##Benefícios

  • Essa técnica de refatoração é uma saída para situações em que um campo com um tipo codificado muda de valor durante o tempo de vida do objeto. Nesse caso, a substituição do valor é feita por meio da substituição do objeto de estado ao qual a classe original se refere.

  • Se você precisar adicionar um novo valor de um tipo codificado, tudo o que precisa fazer é adicionar uma nova subclasse de estado sem alterar o código existente (cf. o Princípio Aberto/Fechado).

##Como refatorar

  1. Use Autoencapsular Campo para criar um getter para o campo que contém o código de tipo.

  2. Crie uma nova classe e dê a ela um nome compreensível que se ajuste ao propósito do código de tipo. Essa classe desempenhará o papel de estado (ou estratégia). Nela, crie um getter abstrato para o campo codificado.

  3. Crie subclasses da classe de estado para cada valor do tipo codificado. Em cada subclasse, redefina o getter do campo codificado para que ele retorne o valor correspondente do tipo codificado.

  4. Na classe de estado abstrata, crie um método fábrica estático que aceite o valor do tipo codificado como parâmetro. Dependendo desse parâmetro, o método fábrica criará objetos de vários estados. Para isso, em seu código crie um grande condicional; ele será o único quando a refatoração estiver concluída.

  5. Na classe original, mude o tipo do campo codificado para a classe de estado. No setter do campo, chame o método fábrica de estado para obter novos objetos de estado.

  6. Agora você pode começar a mover os campos e métodos da superclasse para as subclasses de estado correspondentes (usando Descer Campo e Descer Método).

  7. Quando tudo o que é movível tiver sido movido, use Substituir Condicional por Polimorfismo para se livrar de uma vez por todas dos condicionais que usam código de tipo.