ConstructiCat Logo
CodeBust.
Browse section ▾

Substituir Código de Tipo por Subclasses.

Problem

Você tem um tipo codificado que afeta diretamente o comportamento do programa (os valores desse campo disparam diversos trechos de código em condicionais).

Solution

Crie subclasses para cada valor do tipo codificado. Em seguida, extraia os comportamentos relevantes da classe original para essas subclasses. Substitua o código de controle de fluxo por polimorfismo.

##Example

Antes
Employee +ENGINEER : int$+SALESMAN : int$+type : int
Depois
Employee Engineer Salesman

##Why Refactor

Esta técnica de refatoração é uma variação mais complicada de Substituir Código de Tipo por Classe.

Como no primeiro método de refatoração, você tem um conjunto de valores simples que constituem todos os valores permitidos para um campo. Embora esses valores muitas vezes sejam especificados como constantes e tenham nomes compreensíveis, seu uso torna seu código muito propenso a erros, já que eles ainda são primitivos na prática. Por exemplo, você tem um método que aceita um desses valores em seus parâmetros. Em determinado momento, em vez da constante USER_TYPE_ADMIN com o valor "ADMIN", o método recebe a mesma string em letras minúsculas ("admin"), o que causará a execução de algo diferente do que o autor (você) pretendia.

Aqui estamos lidando com código de controle de fluxo, como os condicionais if, switch e ?:. Em outras palavras, campos com valores codificados (como $user->type === self::USER_TYPE_ADMIN) são usados dentro das condições desses operadores. Se usássemos Substituir Código de Tipo por Classe aqui, todas essas construções de controle de fluxo seriam melhor movidas para uma classe responsável pelo tipo de dado. Em última análise, isso obviamente criaria uma classe de tipo muito semelhante à original, com os mesmos problemas também.

##Benefits

  • Elimina o código de controle de fluxo. Em vez de um switch volumoso na classe original, mova o código para as subclasses apropriadas. Isso melhora a aderência ao Princípio da Responsabilidade Única e torna o programa mais legível em geral.

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

  • Ao substituir o código de tipo por classes, abrimos caminho para a tipagem (type hinting) de métodos e campos no nível da linguagem de programação. Isso não seria possível usando simples valores numéricos ou de string contidos em um tipo codificado.

##How to Refactor

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

  2. Torne o construtor da superclasse privado. Crie um método de fábrica estático com os mesmos parâmetros do construtor da superclasse. Ele deve conter o parâmetro que receberá os valores iniciais do tipo codificado. Dependendo desse parâmetro, o método de fábrica criará objetos de várias subclasses. Para isso, em seu código você precisará criar uma grande condicional, mas, ao menos, ela será a única quando for realmente necessária; caso contrário, as subclasses e o polimorfismo darão conta.

  3. Crie uma subclasse única para cada valor do tipo codificado. Nela, redefina o getter do tipo codificado para que ele retorne o valor correspondente do tipo codificado.

  4. Exclua o campo com o código de tipo da superclasse. Torne seu getter abstrato.

  5. Agora que você tem subclasses, pode começar a mover os campos e métodos da superclasse para as subclasses correspondentes (com a ajuda de Descer Campo e Descer Método).

  6. Quando tudo o que for possível tiver sido movido, use Substituir Condicional por Polimorfismo para se livrar de uma vez por todas das condições que usam o código de tipo.