O processo de refactoring é uma atividade que realiza mudanças no código-fonte de uma aplicação, mas sem alterar o comportamento e propósito inicial do software. A técnica de refactoring deve ser aplicada quando o desenvolvedor realiza modificações estruturais no software, as quais afetem todas as referências a um recurso modificado, tais referências são encontradas nos arquivos de código-fonte da aplicação. Podemos entender as técnicas de refactoring como um processo de aperfeiçoamento do código-fonte de uma classe sob diversas perspectivas, tais como: clareza, otimização ou padronização de código.

A NetBeans [1][2] utiliza um módulo integrado a IDE para suporte ao processo de refactoring de aplicações. Esse módulo adota um framework que disponibiliza uma série de facilidades para implementação de modificações de código, desde a versão 4.0 da ferramenta [3]. O módulo é responsável por modificações que refletem alterações na arquitetura das aplicações desenvolvidas. A ferramenta NetBeans IDE utiliza um repositório de meta informações para manter informações acerca da arquitetura do software em desenvolvimento. A infra-estrutura do repositório de informações implementa a MOF (Meta Object Facility) proposta pela OMG (Object Management Group), trata-se de um modelo que visa a padronização de repositórios de metadados. O grupo Netbeans.org mantém um projeto denominado MDR (Metadata Repository) [4] que é responsável pela integração do modelo de repositório de metadados em ferramentas da plataforma NetBeans.

Entre as motivações do projeto MDR podemos encontrar:

  • Concepção de um código-fonte claro e de fácil manutenção;
  • Redução da complexidade da aplicação;
  • Remoção de redundâncias desnecessárias;
  • Propiciar a reutilização de código;
  • Otimizar e melhorar a performance do software.

Todas as operações de refactoring são avaliadas pela NetBeans IDE, permitindo ao desenvolvedor uma visualização prévia das alterações do código e onde serão refletidas as mudanças antes da aplicação do processo. A tabela 1 apresenta uma breve descrição das operações suportadas atualmente pelo módulo de atualização de código provido pela ferramenta.

Operação Descrição
Rename Permite a alteração do nome (identificador) de uma classe, variavel, ou método. A alteração é propaganda em todo código que realize alguma referência ao identificador alterado.
Extract Method Essa operação gera um novo método a apatir do código previamente selecionado pelo desenvolvedor através do editor de código-fonte integrado ao ambiente de desenvolvimento.
Change Method Parameters Modifica os parâmetros de um método, refletindo a mudança em todos os código que realizam chamada ao mesmo.
Encapsulate Fields Gera os métodos get e set para os atributos de uma classe, atualizando todas as referências aos atributos em códigos associados
Pull Up Move métodos ou campos para a superclasse da classe em questão.
Push Down Move classes internas, métodos, ou campos para a especialização da classe corrente.
Move Class Move uma classe para outro pacote ou classe. Dessa forma, todas as referências a classe em questão são atualizadas.
Move Inner to Outer Level Move uma classe interna para um nível acima da hierarquia de classes a qual a mesma faz parte.
Convert anonymous class to Inner Converte uma classe anônima a uma classe interna, especificando-se um identificador e um constructor. Todas as referências à classe anônima serão atualizadas.
Extract Interface Cria uma nova interface a partir de um método não público e estático selecionado em uma classe ou interface.
Extract Superclass Cria uma nova classe abstrata, modificando a classe corrente para que a mesma estenda a nova classe e move os métodos e atributos selecionados para a nova classe.
Use Supertype Where Possible Modifica todo código que referencia a classe selecionada (ou interface), referenciando o tipo de sua superclasse
Safely Delete Verifica se existe alguma referência a um determinado código (classe, interface, etc), caso não exista, remove o código.
Tabela 1. Operações suportadas pelo módulo de refactoring da NetBeans IDE.

Estudo de Caso

Para exemplificação da utilização das operações de refactoring providas pela NetBeans IDE, será utilizada uma hierarquia que implementa o modelo de classes de contas bancárias que servirá como base para um estudo de caso. O diagrama de classes, apresentado através da figura 1, ilustra o modelo conceitual da hierarquia de contas bancárias.

Diagrama-de-classes-da-hierarquia-de-contas-bancárias
Figura 1. Diagrama de classes da hierarquia de contas bancárias

Note, através da figura anterior, que uma determinada conta bancária pode ser simples. Neste caso, os objetos serão instanciados a partir da classe “Conta”, a qual define uma estrutura básica para todos os elementos do tipo conta bancária. A partir do modelo de conta inicial, serão derivadas as seguintes especializações: “Especial” e “Poupança”; uma conta do tipo especial incrementa uma nova característica que é o limite e realiza um polimorfismo do método debita, acrescentando um comportamento distinto de sua superclasse; já as contas do tipo poupança acrescentam a característica aniversário, a qual será utilizada para realização de uma operação particular a essa classe denominada corrige, a qual será utilizada para atualização do saldo da poupança. A Implementação em Java das estruturas abstratas apresentadas no modelo anterior, podem ser visualizadas através da figura 2, ilustrada logo abaixo.

Código-fonte-das-classes-do-modelo
Figura 2. Código-fonte das classes do modelo.

Com base no modelo conceitual e sua implementação em Java, veremos a aplicação das operações providas pelo modúlo de refactoring. Dessa forma, as próximas seções descreverão e exemplificarão, em mais detalhes, cada operação descrita na tabela 1.

Rename

Conforme descrito anteriormente, podemos realizar operações para alteração do identificador de elementos de um código-fonte, tais como: classes, interfaces, atributos e métodos. Sendo assim, todas as referências ao elemento modificado deverão utilizar o novo identificador aplicado durante a operação “Rename”. Vejamos como aplicar o conceito, renomeando a classe “Pessoa” para “Indivíduo”. Para realização dessa operação, realize os seguintes passos:

  1. selecione o nome da classe, a partir do editor de código-fonte;
  2. clique com o botão direito do mouse sobre a mesma e no menu de contexto que surgirá selecione a opção refactor -> rename, veja a figura 3;
  3. Selecionando-a-operação-Rename-através-do-menu-de-contexto
    Figura 3. Selecionando a operação Rename através do menu de contexto.
  4. Será apresentada a caixa de diálogo Rename, conforme figura 4;
  5. Caixa-de-diálogo-da-operação-Rename
    Figura 4. Caixa de diálogo da operação Rename.
  6. Se desejar alterar as referências em comentários, selecione “Apply Rename on Comments”;
  7. Se quiser uma visualização das alterações antes de realizar a operação, selecione “Preview All Changes”;
  8. Clique no botão Next para realizar a operação;
  9. Se a caixa “Preview All Changes” foi marcada, a caixa de diálogo ilustrada através da figura 5 será apresentada; caso contrário as alterações serão realizadas.
  10. Visualização-prévia-do-resultado-da-operação-Rename.
    Figura 5. Visualização prévia do resultado da operação Rename.
  11. Na caixa de diálogo de previsão das alterações, quando apresentada, o desenvolvedor poderá optar por cancelar a operação clicando em Cancel, ou então executar a operação clicando em “Do Refactoring”.

Veja que a renomeação da classe “Pessoa” será propagada à classe “Conta”, visto que uma conta implementa um objeto do tipo “Pessoa” através do identificador do titular da conta. A figura 5 elucida este conceito, podemos observar através da visualização prévia que a referência ao titular da conta também será modificada.

A operação “Rename” pode ser utilizada para outros recursos de uma classe ou interface, tais como: atributos e métodos. Para fixação desse tópico, altere o identificador do atributo nome descrito na estrutura da classe “Conta” e observe o efeito.

Encapsulate Fields

Uma outra operação interessante e muito útil na rotina do desenvolvedor é a Encapsulate Fields. Trata-se de uma operação que acelera o trabalho de codificação da estrutura de uma classe, pois a mesma gera automaticamente o código dos métodos get e set. Vejamos a seguir os passos necessários para a execução dessa operação. Para isso, utilizaremos a classe “Pessoa”, a qual ainda não apresenta os métodos get e set definidos em sua estrutura.

  1. Selecione o nome da classe através do editor de código-fonte;
  2. lique com o botão direito do mouse sobre a mesma e no menu de contexto que surgirá selecione a opção refactor -> Encapsulate Fields, veja a figura 6;
  3. Gerando-os-métodos-get-e-set-através-da-operação-Encapsulate-Fields
    Figura 6. Gerando os métodos get e set através da operação Encapsulate Fields
  4. Será apresentada a caixa de diálogo Encapsulate Fields, conforme a ilustração da figura 7;
  5. A-caixa-de-diálogo-Encapsulate-Fields.
    Figura 7. A caixa de diálogo Encapsulate Fields.
  6. A tabela apresentada na caixa de diálogo monta uma lista de atributos da classe “Pessoa” e duas colunas, onde o desenvolvedor irá marcar se deseja que sejam gerados os métodos get e set respectivamente;
  7. Além disso, o desenvolvedor poderá definir o nível de visibilidade de cada atributo (public, private, protected ou default) através da opção “Field's Visibility”;
  8. O grau de visibilidade dos métodos get e set poderá ser definido através da opção “Accessor's Visibility”;
  9. A opção “Use Accessors Even When Field Is Accessible” irá modificar as referências aos atributos da classe quando marcada. Dessa forma, as referências serão modificadas para fazer uso dos métodos get e set gerados.
  10. Assim como na operação “Rename”, quando marcada a opção “Preview All Changes”, uma prévia será apresentada antes da efetivação da operação.

A figura 8 demonstra o resultado de “Encapsulate Fields”, onde pode-se observar o código de cada método get e set gerado automaticamente pela operação.

Reestruturação-do-código-fonte-da-classe-Pessoa
Figura 8. Reestruturação do código-fonte da classe Pessoa, com a presença dos métodos get e set.

No próximo artigo daremos continuidade à apresentação das funções de refactoring providas pela NetBeans IDE, onde poderemos observar o conjunto de facilidades que irão auxiliar na estruturação do código-fonte de nossos softwares, bem como auxilar no processo de modificação dos elementos das nossas aplicações.

Leia também