Refactoring
Visão Geral do Catálogo
de Martin Fowler
Jorge Fernandes
Janeiro de 2001
Catálogo de Refactorings
• Composição de Métodos
• Movendo Características entre Objetos
• Organizando Dados
• Simplificando Expressões Condicionais
• Simplificando Invocação de Métodos
• Tratando com Generalização
Composição de Métodos
(Fowler, 1999)
• O principal refactoring é Extract Method, que transforma
um pedaço de código em um novo método. Inline
Method é a operação oposta, usada quando a existência
do método não faz mais sentido.
• Quando surgem problemas com variáveis locais é
interessante tentar aplicar Replace Temp with Query.
Eventualmente as variáveis apresentam interdependência
e a solução pode ser Replace Method with Method
Object que implica na criação de uma nova classe.
Outros problemas na extração de método podem ser
resolvidos com Remove Assignments to Parameters.
• Uma vez que o método esteja fatorado, a clareza do
algoritmo pode ser melhorada com Substitute
Extract Method
Transformar este código ...
void printOwing(double amount) { printBanner(); // print details System.out.println(“name:”+ _name); System.out.println(“amount” + amount); } … neste!
void printOwing(double amount) { printBanner();
printDetails(amount); }
void printDetails(double amount) { System.out.println(“name:”+
_name);
System.out.println(“amount” + amount);
Extract Method
Mecânica (Algoritmo)
Crie um novo método e o nomeie-o adequadamente (pelo que ele faz, e não como ele o faz)
Copie o código extraído da fonte no
(método) destino
Dê uma varrida no código extraído para referências a quaisquer variáveis temporárias (locais e parâmetros) que estão no escopo do método fonte.
Veja as variáveis temporárias usadas apenas no escopo do método extraído e declare-as no método destino.
Verifique se apenas uma das outras variáveis temporárias é modificada no escopo do código extraído. Veja então se dá para usar o método novo como uma query. Caso haja mais de uma destas variáveis ou caso a query não fique adequada aplique Split Temporary Variable ou Replace Temp with Query.
Passe como parâmetro para o método destino as variáveis temporárias que são apenas lidas
Compile quando tiver resolvido todos os problemas com variáveis
Substitua o código extraído no método fonte com uma chamada ao método destino.
Movendo Características entre
Objetos (Fowler, 1999)
• Problemas com atribuição adequada de responsabilidades a objetos começam a ser resolvidos aplicando-se Move Field e Move Method. • Quando classes ficam abarrotadas de responsabilidades pode-se
usar Extract Class para separá-las. Ao contrário, quando classes ficam irresponsáveis pode-se usar Inline Class.
• Uma classe que está sendo usada por outra pode ser escondida
através de Hide Delegate. Se esta operação implicar em mudanças constantes na interface da classe da frente pode ser preciso Remove
Middle Man.
• Introduce Foreign Method e Introduce Local Extension são
aplicados em casos especiais, quando se deseja mover
responsabilidades para uma classe, mas não é possível se acessar o código fonte desta.
Organizando Dados (1 de 3)
• Se você normalmente usa acesso direto a um atributo mas necessita de um acessor então aplique Self Encapsulate Field.
• Use Replace Data Value with Object quando você começou com um simples dado e porteriormente se deu conta de que um objeto poderia ser mais útil. Caso estes objetos sejam usados em muitas partes do programa então Change Value to Reference.
• Se você vê um array funcionando como uma estrutura de dados então Replace Array with Object. A vantagem real desta
transformação surge quando se usa Move Method para adicionar comportamento aos novos objetos.
• Uma vez que tenha percebido qual a finalidade dele, Replace Magic
Organizando Dados (2 de 3)
• Links entre objetos podem ser uni- ou bi-direcionais.
Embora os primeiros sejam mais fáceis, eventualmente é
necessário Change Unidirectional Association to
Bidirectional para prover suporte a novas funções. A
operação inversa, Change Bidirectional Association to
Unidirectional, pode simplificar a solução.
• Duplicate Observed Data pode ser necessário quando
se deseja separar dados do domínio dos dados de uma
classe de GUI.
• Se qualquer dado público está exposto por aí
Encapsulate Field. Se o dado é uma coleção então
Encapsulate Collection. Se um registro inteiro está
Organizando Dados (3 de 3)
• Códigos de tipo indicam particularidades sobre a condição de um objeto. Replace Type Code with Class quando este código não implica em mudanças no comportamento da classe. Replace Type
Code with Subclass quando o comportamento se altera. Outra
alternativa mais complicada é Replace Type Code with
Simplificando Expressões
Condicionais
• Decompose Conditional separa um condicional em
partes, isolando a código de chaveamento das
conseqüências deste chaveamento.
• Consolidate Conditional Expression quando vários
testes produzem o mesmo efeito. Consolidade
Duplicate Conditional Fragment remove duplicações no
código condicional.
• Para tornar mais claro um condicional Replace Nested
Conditional with Guard Clauses e Remove Control
Flag.
• Observe sempre se é possível Replace Conditional with
Polymosphism, inclusive através de Introduce Null
Object.
Simplificando Invocação de Métodos
(1 de 2)
• A transformação mais simples e importante é Rename
Method.
• Add Parameter ou Remove Parameter para transformar
interfaces.
• Se muitos parâmetros são passados numa chamada,
Preserve Whole Object evita esta passagem, Introduce
Parameter Object cria um local adequado para estes
parametros, ou então Replace Parameter with Method.
• Se algum dos parâmetros é usado para condicionar o
comportamento do método, então Replace Parameter
with Explicit Method.
• Separate Query from Modifier, sempre que encontrá-los
juntos.
Simplificando Invocação de Métodos
(2 de 2)
• Esconda ou remova métodos sempre que puder com Hide Method e
Remove Setting Method.
• Para evitar o conhecimento prematuro da classe de um objeto a ser criado, use Replace Constructor with Factory Method.
• Evite usar casts explícitos através de Encapsulate Downcast.
• Replace Error Code with Exception ou Replace Exception with
Tratando com Generalização
(1 de 2)
• Use Pull Up Field e Pull Up Method para promover uma função na hierarquia de classes, ou Push Down Method e Push Down Field para rebaixá-la.
• Use Pull Up Constructor Body para promover construtores, que é o caminho inverso de Replace Constructor with Factory Method. • Métodos que apresentam similaridades mas variam nos detalhes
Tratando com Generalização
(2 de 2)
• Extract Subclass, Extract Superclass e Extract Interface
modificam hierarquia através da criação de novas classes.
• Classes desnecessárias podem ser removidas através de Collapse
Hierarchy.
• Quando herança não é a melhor forma de design, Replace
Inheritance with Delegation. O caminho contrário é Replace Delegation with Inheritance.
Grandes Refactorings
• Tease Apart Inheritance quando você tem uma hierarquia de
herança que realiza dois trabalhos ao mesmo tempo.
• Convert Procedural Design to Objects quando você tem código
escrito em estilo procedural.
• Separate Domain from Presentation quando você tem classes de
GUI que contém lógica do domínio.
• Extract Hierarchy quando você tem uma classe que está fazendo
muito trabalho, principalmente através de muitos comandos condicionais.