Desenvolvimento
Baseado em Testes
Refatoração
Agenda
• Refatoração	

• Exemplos	

• Técnicas de Refatoração
2
Refatoração
O que é?
• “É o processo de realizar mudanças
em código existente e funcional sem
alterar seu comportamento”	

!

• Alterar COMO o código	

• NÃO alterar O QUE ele faz	

!

• Aprimorar a estrutura interna
Qual a relação com
TDD?
Refatoração
e TDD
• Após implementar o código mais simples
para fazer o teste passar	


• refatoramos o código para remover as

duplicações que adicionamos para ver o
teste passar	


• Como temos um conjunto seguro de
testes,	


• então podemos refatorar com confiança
O que nos motiva a
refatorar?
Motivação
• facilitar a adição de código novo	

• melhorar o projeto existente	

• obter um melhor entendimento de código	

• tornar a programação menos irritante
Quando refatorar?
Contextos
• quando existe duplicação de código	

• quando a intenção é obscura
• percebemos que o código e/ou sua
intenção não são claros

• ex: lógica condicional complicada	


• quando detectamos problemas de código
(“bad smells”)	


• ou indícios de problemas
Duplicação
• Falência de um bom código	

• Existem várias formas	

• simples e óbvios	

• índícios	

• disfarçados
Say Everything Once and Only Once
!

Don’t Repeat Yourself
Diga tudo uma vez e apenas uma vez
!

Não se repita
Exemplos
Duplicação: 1.º exemplo
def save	
	 if (arquivo.nil?)	
	 	 return false	
	 end	
	 diretorio = Diretorio.new(arquivo)	
	 diretorio.add(arquivo)	
	 diretorio.close()	
	 return true	
end	

	
	
	
	
	
	
	
	
	
	

def saveAs	
	 arquivo = view.file	
	 	
	 if (arquivo.nil?) 	
	 	 return false	
	 end	
	 diretorio = Diretorio.new(arquivo)	
	 diretorio.add(arquivo)	
	 diretorio.close()	
	 return true	
end
def save	
	 if (arquivo.nil?) {	
	 	 return false	
	 }	
	 diretorio = Diretorio.new(arquivo)	
	 diretorio.add(arquivo)	
	 diretorio.close()	
	 return true	
end	

	
	
	
	

def saveAs	
	 arquivo = view.file	
	 	
	 save	
end
Duplicação: 2.º exemplo
class MovieList 	
	 def initialize	
	 	 @movies = []	
	 	 @number_of_movies = 0	
	 end	
	 	
	 def size	
	 	 @movies.size	
	 end	
	 	
	 def add movie_to_add	
	 	 @movies  movie_to_add	
	 	 @number_of_movies = @number_of_movies + 1	
	 end	
end
class MovieList 	
!
	 def initialize	
	 	 @movies = []	
	 	 @number_of_movies = 0	
	 end	

!
def size	 	
	 @movies.size	
end	
	
def add movie_to_add 	
@movies  movie_to_add	
end	
!
end
Intenção obscura
O que torna um código
claro?
• Escolher bons nomes
• dicionário na mão para ajudar a
comunicar nossa intenção	


• TDD	

• Como escrevemos 1º o teste, somos
forçados a pensar na interface do
código antes da sua implementação	


• oportunidade de pensar a partir do

ponto de vista do usuário da classe
Problemas de código
Code Smells
Bad Smells
•
•
•
•

Excesso de comentários	

Classes de dados	

Código duplicado	

Intimidade inapropriada	

!
!
!

•
•
•
•

Classes muito grandes	

Classes “preguiçosas”	

Métodos longos	

Switches
Excesso de
comentários
def init
// set the layout
content_pane.layout(FlowLayout.new)
!
// create the list
movie_list = List.new(my_editor.movies)
scroller = ScrollPane.new(movie_list)
content_pane.add(scroller)
!
// create the field
movie_field = TextField.new(16)
content_pane.add(movie_field)
!
// create theadd button
add_button = Button.new(“Add)
....
end
Classes de dados
class Ponto 	
	 attr_accessor :x, :y	
	 	
	 def initialize(x = 0, y = 0) 	
	 	 @x = x;	
	 	 @y = y;	
	 end	
	 	
end
Com intimidade
def temperatura
t = estacao.termometro
t.temperatura
end
Sem intimidade
def temperatura
estacao.temperatura
end
Classes muito grandes
• Desproporcional às outras	

• Por quê?	

• tenta fazer muita coisa?	

• possui muito código condicional?	

• possui muito comportamento
condicional?	


• Como identificar?
Classes “preguiçosas”

• Classes tão pequentas que não justificam
sua existência	


• Devem ser fundidas à outras classes
Switches
class Empregado
// 0 - engenheiro, 1 - vendedor, 2 - gerente
attr_accessor :tipo_empregado
!

def nome_do_departamento
case @tipo_empregado
when 0
return Engenheiro
when 1	

return Vendedor
when 2
return Gerente
else
return Desconhecido
end
end
end
Dica
•

Princípios de Orientação
a objetos	


•

Design Patterns
Como refatorar?
Como refatorar
1. Estrutura de testes que proporcionem
feedback	

2. Pequenos passos	

3. IDEs
Técnicas de refatoração
Refatorações
•
•
•
•
•

Extrair classe	

Extrair interface	

Extrair método	

Substituir código
digitado por subclasses
ou objeto de valor	

Substituir condicional
por polimorfismo	


•

Utilizar métodos
gabaritos	


•

Utilizar variavel
explicativa	


•

Substituir construtores
por métodos fábrica	


•

Substituir herança por
delegação	


•

Substituir números
mágicos por constantes
Extrair Classe
• Contexto	

• classes muito grandes	

• comportamento disperso	

• Solução	

• fracionar as classes em pedaços menores
mais coesos	


• Extração de comportamentos para uma
nova classe
class MovieListWriter 	
	 attr_accessor :destination	

!
	
	
	

def initialize(aWriter = nil) 	
	 destination = aWriter;	
end	

!
	
	
	
	
	

def write_movie_list(a_list) 	
	 a_list.movies.each do |movie|	
	 	 write_movie(movie)	
	 end	
	 	
end	

!
	 def write_movie(a_movie)	
	 	 destination.write(a_movie.name)	
	 	 destination.write('|')	
	 	 destination.write(a_movie.category.to_s)	
	 	 destination.write('|')	
	 	 begin	
	 	 	 destination.write(a_movie.rating.to_s)	
	 	 rescue UnratedException = ex	
	 	 	 destination.write(-1)	
	 	 end	
	 	 destination.write('n')	
	 end	
end
class Movie 	
	 // ...	
	 def write_to(destination)

	
	 	 destination.write(name)	
	 	 destination.write('|')	
	 	 destination.write(category.to_s)	
	 	 destination.write('|')	
	 	 begin 	
	 	 	 destination.write(rating.to_s)	
	 	 rescue UnratedException = ex	
	 	 	 destination.write(-1)	
	 	 end	
	 	 destination.write('n');	
	 end	
	 // ...	
end
class MovieList 	
	 	
	 write_to(destination)

	 	 	 movies.each do |movie|	
	 	 	 	 movie.write_to(destination)	
	 	 	 end	
	 end	 	
end
Extrair Interface
• Contexto	

• Se quer abstrair a forma de uma
implementação concreta	


• Comportamentos importantes
substituíveis ou reversíveis	


• Solução	

• criar interfaces para poder substituir o
concreto tardiamente
public class MovieList {	
	 private CollectionMovie movies =	
	 	 new ArrayListMovie();	
!

	
	
	
	
	
	
	
}

public int size() {	
	 return movies.size();	
}	
	
public void add(Movie movieToAdd) {	
	
movies.add(movieToAdd);	
}
public interface IMovieList {	
!

	 public abstract int size();	
!

	 public abstract void add(Movie movie);	
!

}
public class MovieList

implements IMovieList {	
//...	
}
Strategy
Extrair Método
• Contexto	

• métodos muito longos	

• lógicas de complexo entendimento	

• Solução	

• fracionar o método em métodos
menores mais coesos	


• Extração de comportamentos para novos
métodos
public void init() {

}

getContentPane().setLayout(new FlowLayout());
movieList = new JList(myEditor.getMovies());
JScrollPane scroller = new JScrollPane(movieList);
getContentPane().add(scroller);
movieField = new JTextField(16);
getContentPane().add(movieField);
addButton = new JButton(Add);
....
public void init() {
// set the layout
getContentPane().setLayout(new FlowLayout());
!
// create the list
movieList = new JList(myEditor.getMovies());
JScrollPane scroller = new JScrollPane(movieList);
getContentPane().add(scroller);
!
// create the field
movieField = new JTextField(16);
getContentPane().add(movieField);
!
// create theadd button
addButton = new JButton(Add);
....
}
public void init() {
setLayout();
initMovieList();
initMovieField();
initAddButton();
}	

private void setLayout() {
getContentPane().setLayout(new FlowLayout());
}	

private void initMovieList() {
movieList = new JList(getMovies());
JScrollPane scroller = new JScrollPane(movieList);
getContentPane().add(scroller);
}	

private void initMovieField() {
movieField = new JTextField(16);
getContentPane().add(movieField);
}	

private void initAddButton() {...
Extrair Método 2
• Se um trecho de código duplicado
diferentes do programa
Classe1
Extrair Método 2
•

Se as duplicatas de código devem permanecer
sempre iguais, ou seja, uma vez que se realize uma
alteração em uma delas, as demais devem refletir
a alteração
Classe1
public void doGet(HttpservletRequest request,
HttpServletResponse response)
throws ServletException, IOException{
String p = request.getParameter(“personagem”);
request.setAttribute(“personagem”, p);
//Mais código
}
!
public void doPost(HttpservletRequest request,
HttpServletResponse response)
throws ServletException, IOException{
String p = request.getParameter(“personagem”);
request.setAttribute(“personagem”, p);
//Mais código
}
•

Extraindo o método

Concentre o código que se repete em um único
lugar, por exemplo, em um método e leve as
dependências para lá

public void doGet(HtttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException{
String p = request.getParameter(“personagem”);
request.setAttribute(“personagem”, p);
//Mais código
}
public void novoMetodo(HtttpServletRequest request,
HttpServletResponse response)throws ServletException,
IOException{
String p = request.getParameter(“personagem”);
request.setAttribute(“personagem”, p);
//Mais código
}
public void novoMetodo(HttpServletRequest
request, HttpServletResponse response)
throws ServletException, IOException{
.....
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException{
novoMetodo(request, response);
}
!

public void doPost(HttpservletRequest
request, HttpServletResponse response)
throws ServletException, IOException{
novoMetodo(request, response);
}
Refatorações
•
•
•
•
•

Extrair classe	

Extrair interface	

Extrair método	

Substituir código
digitado por subclasses
ou objetos de valor	

Substituir condicional
por polimorfismo	


•

Utilizar métodos
gabaritos	


•

Utilizar variavel
explicativa	


•

Substituir construtores
por métodos fábrica	


•

Substituir herança por
delegação	


•

Substituir números
mágicos por constantes
Substituir código
digitado por subclasses
• Contexto	

• classes indicam subtipos através de
código digitado	


• Solução	

• Criar uma subclasse para cada alternativa	

• Vantagem	

• Evitam-se complexos condicionais
class Empregado 	
	 //0 - engenheiro, 1 - vendedor, 2 - gerente	
	 attr_accessor :tipo_do_empregado	
	 //..	
end
class Empregado 	
	 // ...	
end	
!

class Engenheiro  Empregado 	
	 // ...	
end	
!

class Vendedor  Empregado 	
	 // ...	
end	
!

class Gerente  Empregado 	
	 // ...	
end
Substituir condicional
por polimorfismo	

• Contexto	

• classes indicam subtipos através de
código digitado	


• Solução	

• Criar uma subclasse para cada alternativa	

• Vantagem	

• Evitam-se complexos condicionais
public class Empregado 	
	 // 0 - engenheiro, 1 - vendedor, 2 - gerente	
	 attr_accessor :tipo_do_empregado	
!

	 def nome_do_departamento	
	 	 case @tipoDoEmpregado	
	 	 	 when 0	
	 	 	 	 return Engenharia	
	 	 	 when 1	
	 	 	 	 return Vendas	
	 	 	 when 2	
	 	 	 	 return Gerência	
	 	 	 else	
	 	 	 	 return Desconhecido	
	 	 end	
	 end	
end
class Empregado 	
	 def nome_do_departamento	
	 end	
end	
!
class Engenheiro  Empregado 	
	 def nome_do_departamento	
	
Engenharia	
end	
end	
!
class Vendedor  Empregado 	
	 def nome_do_departamento	
	 	 Vendas	
end	
end	
!
class Gerente extends Empregado 	
	 def nome_do_departamento	
	
Gerência	
end	
end
Utilizar métodos
gabaritos	

•

•

Contexto	


•

métodos em subclasses executam passos
similares na mesma ordem

•

os passos são diferentes	


Solução	


•

extraia os passos para métodos com mesma
assinatura	


•
•

crie um método gabarito final na superclasse	

especialize os métodos nas subclasses
Contexto
public class Cafe {
public void prepararReceita(){
ferverAgua();
misturarCafeComAgua();
servirNaXicara();
adicionarAcucarELeite();
}

!
!
!
!
!

public class Cha {

!

public void prepararReceita(){
ferverAgua();
misturarChaComAgua();
servirNaXicara();
adicionarLimao();
}
Utilizar variáveis
explicativas	

•
•

•

Contexto	


•

expressões complexas de se entender	


Solução	


•
•

extrair partes delas	

guardar resultados intermediários em variáveis
bem nomeadas	


Vantagem	


• código de melhor entendimento
def
	 	
	 	
	 	
end

calcular_total	
subtotal.mais(subtotal_taxavel.vezes(0.15)))	
.menos((subtotal().to_f  100.0)	
	 	 ? (subtotal().vezes(0.10)) : 0)
def calcular_total	
	 	 	
	 taxa = subtotal_taxavel().vezes(0.15)	
	 	 	
	 total = subtotal.mais(taxa)	
	 	 	
	 qualificado_ao_desconto = subtotal.to_f  100.0	
	 	 	
	 desconto = qualificadoAoDesconto	
	 	 	 	 	 	 	 ? subtotal.vezes(0.10)	
	 	 	 	 	 	 	 : Dinheiro.new(0.0)	
	 	 	
	 total.menos(desconto)	
}
•

Substituir construtor
por métodos fábrica	

Contexto	


•

existência de diversos construtores para criar
versões diferentes dos objetos	


•
•

•

pode haver confusão por falta de clareza de
intenção do construtor	


Solução	


•

criar métodos fábrica estáticos	


Vantagem	


• código de melhor entendimento
Como fazer
•

Execute um Extrair Método para isolar a lógica do
comportamento	


•
•

o método deve ser de classe	

repasse as dependências	


•
•

Se o método fábrica não estiver no objeto desejado, utilize o
Mover Método	


•
•

Teste	


Teste	


Remova o construtor original se não há chamadas a ele
Extrair Método
Mover Método
Outra maneira	

Java
public class Avaliacao {	
	 private int valor = 0;	
	 private String revisor = null;	
	 private String revista = null;	
!
	 public Avaliacao(int umaAvaliacao) {	
	 	 this(umaAvaliacao, Anonimo, );	
	 }	
!
	 public Avaliacao(int umaAvaliacao, String umRevisor) {	
	 	 this(umaAvaliacao, umRevisor, );	
	 }	
!
	 public Avaliacao(	
int umaAvaliacao, String umRevisor, String umaRevista) {	
	 	 valor = umaAvaliacao;	
	 	 revisor = umRevisor;	
	 	 revista = umaRevista;	
	 }	
	 // ...	
}
public static Avaliacao novaAvaliacaoAnonima(int valor) {	
	 return new Avaliacao(valor, Anonimo, );	
}	
!
public static Avaliacao novaAvaliacao(int valor, String revisor) {	
	 return new Avaliacao(valor, revisor, );	
}	
!
public static Avaliacao novaCritica(	
int valor, String revisor, String revista) {	
return new Avaliacao(valor, revisor, revista);	
}	
!
private Avaliacao(	
int umaAvaliacao, String umRevisor, String umaRevista) {	
valor = umaAvaliacao;	
revisor = umRevisor;	
revista = umaRevista;	
}
starWars.adicionarAvaliacao(new Avaliacao(2));	
starWars.adicionarAvaliacao(new Avaliacao(4, Joel Barbosa));	
starWars.adicionarAvaliacao(	
new Avaliacao(5, PH Santos, TechTudo));
starWars.adicionarAvaliacao(	
Avaliacao.novaAvaliacaoAnonima(2));	
!
starWars.adicionarAvaliacao(	
Avaliacao.novaAvaliacao(4, Joel Barbosa));	
!
starWars.adicionarAvaliacao(	
Avaliacao.novaCritica(5, PH Santos, TechTudo));
Substituir herança por
delegação	

•
•

Contexto	


•

uma subclasse utiliza apenas uma parte da
interface de sua superclasse e não reutiliza os
dados	


Solução	


•
•

crie um campo do tipo da superclasse	


•

remova a herança

refatore os métodos que utilizam o
comportamento da superclasse
Substituir números mágicos
por constantes ou enums	

•
•

•

Contexto	


•

valores literais no código que possuem um
significado	


Solução	


•

crie uma constante e nomeie-a com o seu
significado	


•

substitua os valores literais pelas constantes	


Vantagem	


• código de melhor entendimento
def energia_potencial(massa, altura) 	
	 	 massa * altura * 9.81	
end
CONSTANTE_GRAVITACIONAL = 9.81	
	 	
def energia_potencial(massa, altura) 	
	 	 massa * altura * CONSTANTE_GRAVITACIONAL 	
end
Resumo
• Um pouco de refatoração	

• o que é	

• técnicas específicas	

• alguns indicadores	

• Existe problema?	

• Deve-se refatorar em pequenos
incrementos
Bibliografia
• ASTELS, David. Test-Driven Development: A
Pratical Guide. Prentice Hall, 2003.	


• FOWLER, Martin; BECK, Kent; BRANT,

John; Opdyke, William; ROBERTS, Don.
Refactoring: Improving The Design of Existing
Code.	


• KERIEVSKY, Joshua. Refatoração Para

Padrões. Porto Alegre: Bookman, 2008.
Bibliografia
• ASTELS, David. Test-Driven Development: A
Pratical Guide. Prentice Hall, 2003.	


• FOWLER, Martin; BECK, Kent; BRANT,

John; Opdyke, William; ROBERTS, Don.
Refactoring: Improving The Design of Existing
Code.	


• KERIEVSKY, Joshua. Refatoração Para

Padrões. Porto Alegre: Bookman, 2008.

Refatoração

  • 1.
  • 2.
    Agenda • Refatoração • Exemplos •Técnicas de Refatoração 2
  • 3.
  • 4.
    O que é? •“É o processo de realizar mudanças em código existente e funcional sem alterar seu comportamento” ! • Alterar COMO o código • NÃO alterar O QUE ele faz ! • Aprimorar a estrutura interna
  • 5.
  • 6.
    Refatoração e TDD • Apósimplementar o código mais simples para fazer o teste passar • refatoramos o código para remover as duplicações que adicionamos para ver o teste passar • Como temos um conjunto seguro de testes, • então podemos refatorar com confiança
  • 7.
    O que nosmotiva a refatorar?
  • 8.
    Motivação • facilitar aadição de código novo • melhorar o projeto existente • obter um melhor entendimento de código • tornar a programação menos irritante
  • 9.
  • 10.
    Contextos • quando existeduplicação de código • quando a intenção é obscura • percebemos que o código e/ou sua intenção não são claros • ex: lógica condicional complicada • quando detectamos problemas de código (“bad smells”) • ou indícios de problemas
  • 11.
    Duplicação • Falência deum bom código • Existem várias formas • simples e óbvios • índícios • disfarçados
  • 12.
    Say Everything Onceand Only Once ! Don’t Repeat Yourself
  • 13.
    Diga tudo umavez e apenas uma vez ! Não se repita
  • 14.
  • 15.
  • 16.
    def save if(arquivo.nil?) return false end diretorio = Diretorio.new(arquivo) diretorio.add(arquivo) diretorio.close() return true end def saveAs arquivo = view.file if (arquivo.nil?) return false end diretorio = Diretorio.new(arquivo) diretorio.add(arquivo) diretorio.close() return true end
  • 17.
    def save if(arquivo.nil?) { return false } diretorio = Diretorio.new(arquivo) diretorio.add(arquivo) diretorio.close() return true end def saveAs arquivo = view.file save end
  • 18.
  • 19.
    class MovieList def initialize @movies = [] @number_of_movies = 0 end def size @movies.size end def add movie_to_add @movies movie_to_add @number_of_movies = @number_of_movies + 1 end end
  • 20.
    class MovieList ! def initialize @movies = [] @number_of_movies = 0 end ! def size @movies.size end def add movie_to_add @movies movie_to_add end ! end
  • 21.
  • 22.
    O que tornaum código claro? • Escolher bons nomes • dicionário na mão para ajudar a comunicar nossa intenção • TDD • Como escrevemos 1º o teste, somos forçados a pensar na interface do código antes da sua implementação • oportunidade de pensar a partir do ponto de vista do usuário da classe
  • 23.
  • 24.
    Bad Smells • • • • Excesso decomentários Classes de dados Código duplicado Intimidade inapropriada ! ! ! • • • • Classes muito grandes Classes “preguiçosas” Métodos longos Switches
  • 25.
    Excesso de comentários def init //set the layout content_pane.layout(FlowLayout.new) ! // create the list movie_list = List.new(my_editor.movies) scroller = ScrollPane.new(movie_list) content_pane.add(scroller) ! // create the field movie_field = TextField.new(16) content_pane.add(movie_field) ! // create theadd button add_button = Button.new(“Add) .... end
  • 26.
    Classes de dados classPonto attr_accessor :x, :y def initialize(x = 0, y = 0) @x = x; @y = y; end end
  • 27.
    Com intimidade def temperatura t= estacao.termometro t.temperatura end
  • 28.
  • 29.
    Classes muito grandes •Desproporcional às outras • Por quê? • tenta fazer muita coisa? • possui muito código condicional? • possui muito comportamento condicional? • Como identificar?
  • 30.
    Classes “preguiçosas” • Classestão pequentas que não justificam sua existência • Devem ser fundidas à outras classes
  • 31.
    Switches class Empregado // 0- engenheiro, 1 - vendedor, 2 - gerente attr_accessor :tipo_empregado ! def nome_do_departamento case @tipo_empregado when 0 return Engenheiro when 1 return Vendedor when 2 return Gerente else return Desconhecido end end end
  • 32.
    Dica • Princípios de Orientação aobjetos • Design Patterns
  • 33.
  • 34.
    Como refatorar 1. Estruturade testes que proporcionem feedback 2. Pequenos passos 3. IDEs
  • 35.
  • 36.
    Refatorações • • • • • Extrair classe Extrair interface Extrairmétodo Substituir código digitado por subclasses ou objeto de valor Substituir condicional por polimorfismo • Utilizar métodos gabaritos • Utilizar variavel explicativa • Substituir construtores por métodos fábrica • Substituir herança por delegação • Substituir números mágicos por constantes
  • 37.
    Extrair Classe • Contexto •classes muito grandes • comportamento disperso • Solução • fracionar as classes em pedaços menores mais coesos • Extração de comportamentos para uma nova classe
  • 38.
    class MovieListWriter attr_accessor :destination ! def initialize(aWriter = nil) destination = aWriter; end ! def write_movie_list(a_list) a_list.movies.each do |movie| write_movie(movie) end end ! def write_movie(a_movie) destination.write(a_movie.name) destination.write('|') destination.write(a_movie.category.to_s) destination.write('|') begin destination.write(a_movie.rating.to_s) rescue UnratedException = ex destination.write(-1) end destination.write('n') end end
  • 39.
    class Movie // ... def write_to(destination)
 destination.write(name) destination.write('|') destination.write(category.to_s) destination.write('|') begin destination.write(rating.to_s) rescue UnratedException = ex destination.write(-1) end destination.write('n'); end // ... end
  • 40.
    class MovieList write_to(destination)
 movies.each do |movie| movie.write_to(destination) end end end
  • 41.
    Extrair Interface • Contexto •Se quer abstrair a forma de uma implementação concreta • Comportamentos importantes substituíveis ou reversíveis • Solução • criar interfaces para poder substituir o concreto tardiamente
  • 42.
    public class MovieList{ private CollectionMovie movies = new ArrayListMovie(); ! } public int size() { return movies.size(); } public void add(Movie movieToAdd) { movies.add(movieToAdd); }
  • 43.
    public interface IMovieList{ ! public abstract int size(); ! public abstract void add(Movie movie); ! }
  • 44.
  • 45.
  • 46.
    Extrair Método • Contexto •métodos muito longos • lógicas de complexo entendimento • Solução • fracionar o método em métodos menores mais coesos • Extração de comportamentos para novos métodos
  • 47.
    public void init(){ } getContentPane().setLayout(new FlowLayout()); movieList = new JList(myEditor.getMovies()); JScrollPane scroller = new JScrollPane(movieList); getContentPane().add(scroller); movieField = new JTextField(16); getContentPane().add(movieField); addButton = new JButton(Add); ....
  • 48.
    public void init(){ // set the layout getContentPane().setLayout(new FlowLayout()); ! // create the list movieList = new JList(myEditor.getMovies()); JScrollPane scroller = new JScrollPane(movieList); getContentPane().add(scroller); ! // create the field movieField = new JTextField(16); getContentPane().add(movieField); ! // create theadd button addButton = new JButton(Add); .... }
  • 49.
    public void init(){ setLayout(); initMovieList(); initMovieField(); initAddButton(); } private void setLayout() { getContentPane().setLayout(new FlowLayout()); } private void initMovieList() { movieList = new JList(getMovies()); JScrollPane scroller = new JScrollPane(movieList); getContentPane().add(scroller); } private void initMovieField() { movieField = new JTextField(16); getContentPane().add(movieField); } private void initAddButton() {...
  • 50.
    Extrair Método 2 •Se um trecho de código duplicado diferentes do programa Classe1
  • 51.
    Extrair Método 2 • Seas duplicatas de código devem permanecer sempre iguais, ou seja, uma vez que se realize uma alteração em uma delas, as demais devem refletir a alteração Classe1
  • 52.
    public void doGet(HttpservletRequestrequest, HttpServletResponse response) throws ServletException, IOException{ String p = request.getParameter(“personagem”); request.setAttribute(“personagem”, p); //Mais código } ! public void doPost(HttpservletRequest request, HttpServletResponse response) throws ServletException, IOException{ String p = request.getParameter(“personagem”); request.setAttribute(“personagem”, p); //Mais código }
  • 53.
    • Extraindo o método Concentreo código que se repete em um único lugar, por exemplo, em um método e leve as dependências para lá public void doGet(HtttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ String p = request.getParameter(“personagem”); request.setAttribute(“personagem”, p); //Mais código } public void novoMetodo(HtttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{ String p = request.getParameter(“personagem”); request.setAttribute(“personagem”, p); //Mais código }
  • 54.
    public void novoMetodo(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{ ..... } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ novoMetodo(request, response); } ! public void doPost(HttpservletRequest request, HttpServletResponse response) throws ServletException, IOException{ novoMetodo(request, response); }
  • 55.
    Refatorações • • • • • Extrair classe Extrair interface Extrairmétodo Substituir código digitado por subclasses ou objetos de valor Substituir condicional por polimorfismo • Utilizar métodos gabaritos • Utilizar variavel explicativa • Substituir construtores por métodos fábrica • Substituir herança por delegação • Substituir números mágicos por constantes
  • 56.
    Substituir código digitado porsubclasses • Contexto • classes indicam subtipos através de código digitado • Solução • Criar uma subclasse para cada alternativa • Vantagem • Evitam-se complexos condicionais
  • 57.
    class Empregado //0 - engenheiro, 1 - vendedor, 2 - gerente attr_accessor :tipo_do_empregado //.. end
  • 58.
    class Empregado // ... end ! class Engenheiro Empregado // ... end ! class Vendedor Empregado // ... end ! class Gerente Empregado // ... end
  • 60.
    Substituir condicional por polimorfismo •Contexto • classes indicam subtipos através de código digitado • Solução • Criar uma subclasse para cada alternativa • Vantagem • Evitam-se complexos condicionais
  • 61.
    public class Empregado // 0 - engenheiro, 1 - vendedor, 2 - gerente attr_accessor :tipo_do_empregado ! def nome_do_departamento case @tipoDoEmpregado when 0 return Engenharia when 1 return Vendas when 2 return Gerência else return Desconhecido end end end
  • 62.
    class Empregado def nome_do_departamento end end ! class Engenheiro Empregado def nome_do_departamento Engenharia end end ! class Vendedor Empregado def nome_do_departamento Vendas end end ! class Gerente extends Empregado def nome_do_departamento Gerência end end
  • 63.
    Utilizar métodos gabaritos • • Contexto • métodos emsubclasses executam passos similares na mesma ordem • os passos são diferentes Solução • extraia os passos para métodos com mesma assinatura • • crie um método gabarito final na superclasse especialize os métodos nas subclasses
  • 64.
    Contexto public class Cafe{ public void prepararReceita(){ ferverAgua(); misturarCafeComAgua(); servirNaXicara(); adicionarAcucarELeite(); } ! ! ! ! ! public class Cha { ! public void prepararReceita(){ ferverAgua(); misturarChaComAgua(); servirNaXicara(); adicionarLimao(); }
  • 66.
    Utilizar variáveis explicativas • • • Contexto • expressões complexasde se entender Solução • • extrair partes delas guardar resultados intermediários em variáveis bem nomeadas Vantagem • código de melhor entendimento
  • 67.
    def end calcular_total subtotal.mais(subtotal_taxavel.vezes(0.15))) .menos((subtotal().to_f 100.0) ? (subtotal().vezes(0.10)) : 0)
  • 68.
    def calcular_total taxa = subtotal_taxavel().vezes(0.15) total = subtotal.mais(taxa) qualificado_ao_desconto = subtotal.to_f 100.0 desconto = qualificadoAoDesconto ? subtotal.vezes(0.10) : Dinheiro.new(0.0) total.menos(desconto) }
  • 69.
    • Substituir construtor por métodosfábrica Contexto • existência de diversos construtores para criar versões diferentes dos objetos • • • pode haver confusão por falta de clareza de intenção do construtor Solução • criar métodos fábrica estáticos Vantagem • código de melhor entendimento
  • 71.
    Como fazer • Execute umExtrair Método para isolar a lógica do comportamento • • o método deve ser de classe repasse as dependências • • Se o método fábrica não estiver no objeto desejado, utilize o Mover Método • • Teste Teste Remova o construtor original se não há chamadas a ele
  • 72.
  • 75.
  • 77.
  • 78.
    public class Avaliacao{ private int valor = 0; private String revisor = null; private String revista = null; ! public Avaliacao(int umaAvaliacao) { this(umaAvaliacao, Anonimo, ); } ! public Avaliacao(int umaAvaliacao, String umRevisor) { this(umaAvaliacao, umRevisor, ); } ! public Avaliacao( int umaAvaliacao, String umRevisor, String umaRevista) { valor = umaAvaliacao; revisor = umRevisor; revista = umaRevista; } // ... }
  • 79.
    public static AvaliacaonovaAvaliacaoAnonima(int valor) { return new Avaliacao(valor, Anonimo, ); } ! public static Avaliacao novaAvaliacao(int valor, String revisor) { return new Avaliacao(valor, revisor, ); } ! public static Avaliacao novaCritica( int valor, String revisor, String revista) { return new Avaliacao(valor, revisor, revista); } ! private Avaliacao( int umaAvaliacao, String umRevisor, String umaRevista) { valor = umaAvaliacao; revisor = umRevisor; revista = umaRevista; }
  • 80.
    starWars.adicionarAvaliacao(new Avaliacao(2)); starWars.adicionarAvaliacao(new Avaliacao(4,Joel Barbosa)); starWars.adicionarAvaliacao( new Avaliacao(5, PH Santos, TechTudo));
  • 81.
  • 82.
    Substituir herança por delegação • • Contexto • umasubclasse utiliza apenas uma parte da interface de sua superclasse e não reutiliza os dados Solução • • crie um campo do tipo da superclasse • remova a herança refatore os métodos que utilizam o comportamento da superclasse
  • 85.
    Substituir números mágicos porconstantes ou enums • • • Contexto • valores literais no código que possuem um significado Solução • crie uma constante e nomeie-a com o seu significado • substitua os valores literais pelas constantes Vantagem • código de melhor entendimento
  • 86.
    def energia_potencial(massa, altura) massa * altura * 9.81 end
  • 87.
    CONSTANTE_GRAVITACIONAL = 9.81 def energia_potencial(massa, altura) massa * altura * CONSTANTE_GRAVITACIONAL end
  • 88.
    Resumo • Um poucode refatoração • o que é • técnicas específicas • alguns indicadores • Existe problema? • Deve-se refatorar em pequenos incrementos
  • 89.
    Bibliografia • ASTELS, David.Test-Driven Development: A Pratical Guide. Prentice Hall, 2003. • FOWLER, Martin; BECK, Kent; BRANT, John; Opdyke, William; ROBERTS, Don. Refactoring: Improving The Design of Existing Code. • KERIEVSKY, Joshua. Refatoração Para Padrões. Porto Alegre: Bookman, 2008.
  • 91.
    Bibliografia • ASTELS, David.Test-Driven Development: A Pratical Guide. Prentice Hall, 2003. • FOWLER, Martin; BECK, Kent; BRANT, John; Opdyke, William; ROBERTS, Don. Refactoring: Improving The Design of Existing Code. • KERIEVSKY, Joshua. Refatoração Para Padrões. Porto Alegre: Bookman, 2008.