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 Grandes Refactorings
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 Algorithm.
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. Compile e teste.
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 Number with Symbolic Constant para se livrar do problema.
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á exposto então Replace Record with Data Class.
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 State/Strategy.
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 Test.
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 podem ser transformados através de Form Template Method.
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.
Refactoring Visão Geral do Catálogo de Martin Fowler Jorge Fernandes Janeiro de 2001