Você está na página 1de 46

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Orientao a Objeto - Regras Bsicas de Design


Objetivos da Seo
Aprender algumas das regras bsicas nas quais o programador deve se apoiar ao projetar software Buscamos princpios de um bom projeto OO Acompanhar um exemplo de refatoramento de software, transformando um software de qualidade pobre num de melhor qualidade

Regras Bsicas de Design


O que Design? uma das partes mais difceis da programao Consiste em criar abstraes Isto significa trs coisas: Quais classes devem ser criadas? Quais responsabilidades (mtodos) devem ser assumidas por cada classe? Quais so os relacionamentos entre tais classes e objetos dessas classes? Criar boas abstraes difcil e vem com experincia Porm, algumas regras bsicas ajudaro a adquirir a experincia mais rapidamente

Responsabilidades
Responsabilidades so obrigaes de um tipo ou de uma classe Obrigaes de fazer algo Fazer algo a si mesmo Iniciar aes em outros objetos Controlar ou coordenar atividades em outros objetos Obrigaes de conhecer algo
1 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Conhecer dados encapsulados Conhecer objetos relacionados Conhecer coisas que ele pode calcular Exemplos Uma Conta bancria tem a responsabilidade de logar as transaes (fazer algo) Uma Conta bancria tem a responsabilidade de saber sua data de criao (conhecer algo)

Regra 1: Keep It Simple, Stupid (KISS)


Lembre de Saint-Exupry: "Atingimos a perfeio no quando nada pode acrescentar-se a um projeto mas quando nada pode retirar-se" Esta a MegaRegra

Regra 2: Colocar as Responsabilidades com os Dados


Qual o princpio mais fundamental para atribuir responsabilidades? este: Atribuir uma responsabilidade ao expert de informao - a classe que possui a informao necessria para preencher a responsabilidade Exemplo: Entre as seguintes classes do mundo bancrio, (Agencia, Conta, ContaCaixa, ContaSimples, Extrato, ExtratoHTML, Moeda, Movimento, Real, Transacao), quem deve ser responsvel pela responsabilidade "Localizar a conta com certo nmero"? Perguntamos: onde esto guardadas as Contas? (onde esto os dados) Esto na Agencia Portanto, a classe Agencia deve ter a responsabilidade (atravs do mtodo localizarConta(int nmero)) Consequncias A encapsulao mantida, j que objetos usam sua prpria informao para cumprir suas responsabilidades
2 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Leva a fraco acoplamento entre objetos e sistemas mais robustos e fceis de manter Leva a alta coeso, j que os objetos fazem tudo que relacionado sua prpria informao Tambm conhecido como: "Quem sabe, faz" "Expert" "Animao" (objetos so vivos e podem assumir qualquer responsabilidade, mesmo que sejam passivos no mundo real) Exemplo: No mundo bancrio real, uma agncia algo passivo e no "localiza contas" "Eu mesmo fao" "Colocar os servios junto aos atributos que eles manipulam"

Regra 3: Fraco Acoplamento


O problema: Como minimizar dependncias e maximizar o reuso? O acoplamento uma medida de quo fortemente uma classe est conectada, possui conhecimento ou depende de outra classe Com fraco acoplamento, uma classe no dependente de muitas outras classes Com uma classe possuindo forte acoplamento, temos os seguintes problemas: Mudanas a uma classe relacionada fora mudanas locais classe A classe mais difcil de entender isoladamente A classe mais difcil de ser reusada, j que depende da presena de outras classes A soluo: Atribuir responsabilidades de forma a minimizar o acoplamento Discusso Minimizar acoplamento um dos princpios de
3 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

ouro do projeto OO Acoplamento de manifesta de vrias formas: X tem um atributo que referencia uma instncia de Y X tem um mtodo que referencia uma instncia de Y Pode ser parmetro, varivel local, objeto retornado pelo mtodo X uma subclasse direta ou indireta de Y X implementa a interface Y A herana um tipo de acoplamento particularmente forte Uma seo futura esmiua o assunto No se deve minimizar acoplamento criando alguns poucos objetos monstruosos (God classes) Exemplo: todo o comportamento numa classe e outras classes usadas como depsitos passivos de informao Exemplo: Ordenao de registros de alunos por matrcula e nome
class Aluno { String nome; long matrcula; public String getNome() { return nome; } public long getMatrcula() { return matrcula; } // etc. } ListaOrdenada listaDeAlunos = new ListaOrdenada(); Aluno novoAluno = new Aluno(...); //etc. listaDeAlunos.add(novoAluno);

Agora, vamos ver os problemas


class ListaOrdenada { Object[] elementosOrdenados = new Object[tamanhoAdequado];

4 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

public void add(Aluno x) { // cdigo no mostrado aqui // ... long matrcula1 = x.getMatrcula(); long matrcula2 = elementosOrdenados[k].getMatrcula(); if(matrcula1 < matrcula2) { // faa algo } else { // faa outra coisa } }

O problema da soluo anterior que h forte acoplamento ListaOrdenada sabe muita coisa de Aluno O fato de que a comparao de alunos feito com a matrcula O fato de que a matrcula obtida com getMatrcula() O fato de que matrculas so long (representao de dados) Como comparar matrculas (com <) O que ocorre se mudarmos qualquer uma dessas coisas? Soluo 2: mande uma mensagem para o prprio objeto se comparar com outro
class ListaOrdenada { Object[] elementosOrdenados = new Object[tamanhoAdequado]; public void add(Aluno x) { // cdigo no mostrado // ... if(x.compareTo(elementosOrdenados[K]) < 0) { // faa algo } else { // faa outra coisa } }

Reduzimos o acoplamento escondendo informao atrs de um mtodo


5 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Problema: ListaOrdenada s funciona com Aluno Soluo 3: use interfaces para desacoplar mais ainda
Interface Comparable { public int compareTo(Object outro); } class Aluno implements Comparable { public int compareTo(Object outro) { // compare registro de aluno com outro return ... } } class ListaOrdenada { Object[] elementosOrdenados = new Object[tamanhoAdequado]; public void add(Comparable x) { // cdigo no mostrado if(x.compareTo(elementosOrdenados[K]) < 0) { // faa algo } else { // faa outra coisa } }

Outro exemplo de reduo de acoplamento: polimorfismo com interfaces Temos vrios tipos de composites (colees) que no pertencem a uma mesma hierarquia ColeoDeAlunos ColeoDeProfessores ColeoDeDisciplinas Temos um cliente comum dessas colees Digamos um selecionador de objetos usado numa interface grfica para abrir uma list box para selecionar objetos com um determinado nome Exemplo: Quero listar todos os alunos com nome "Joo" e exib-los numa list box para escolha pelo usurio
6 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Idem para listar professores com nome "Alfredo" Idem para listar disciplinas com nome "Programao" Queremos fazer um nico cliente para qualquer uma das colees O exemplo abaixo tem polimorfismo em dois lugares
interface SelecionvelPorNome { Iterator getIteradorPorNome(String nome); } interface Nomevel { String getNome(); } classe ColeoDeAlunos implements SelecionvelPorNome { // ... Iterator getIteradorPorNome(String nome) { // ... } } classe Aluno implements Nomevel { // ... String getNome() { ... } } classe ColeoDeProfessores implements SelecionvelPorNome { // ... Iterator getIteradorPorNome(String nome) { // ... } } classe Professor implements Nomevel { // ... String getNome() { ... } } classe ColeoDeDisciplinas implements SelecionvelPorNome { // ... Iterator getIteradorPorNome(String nome) { // ...

7 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

} } classe Disciplina implements Nomevel { // ... String getNome() { ... } }

classe ComponenteDeSeleo { Iterator it; // observe o tipo do parmetro (uma interface) public ComponenteDeSeleo(SelecionvelPorNome coleo, String nome) it = coleo.getIteradorPorNome(nome); // chamada polimrfica } // ... void geraListBox() { response.out.println("<select name=\"nome\" size=\"1\">"); while(it.hasNext()) { int i = 1; // observe o tipo do objeto Nomevel obj = (Nomevel)it.next(); response.out.println("<option value=\"escolha" + i + "\" obj.getNome() + // chamada polimr "</option>"); } response.out.println("</select>"); } } // Como usar o cdigo acima num servlet: // supe que as colees usam o padro Singleton ComponenteDeSeleo cds = new ComponenteDeSeleo(ColeoDeAlunos.getInstance(), "Joo"); cds.geraListBox();

cds = new ComponenteDeSeleo(ColeoDeDisciplinas.getInstance(), "P cds.geraListBox();

Regra 4: Alta Coeso


O problema: Como gerenciar a complexidade? A coeso mede quo relacionados ou focados esto as responsabilidades da classe Tambm chamado coeso funcional
8 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Uma classe com baixa coeso faz muitas coisas no relacionadas e leva aos seguintes problemas: Difcil de entender Difcil de reusar Difcil de manter "Delicada": constantemente sendo afetada por outras mudanas Uma classe com baixa coeso assumiu responsabilidades que pertencem a outras classes e deveriam ser delegadas Soluo: Atribuir responsabilidades que mantenham alta coeso Exemplo: O que acha da classe que segue?
class Angu public // } public // } public // } } class Xpto ... } { static int acharPadro(String texto, String padro) { ... static int mdia(Vector nmeros) { ... static outputStream abreArquivo(string nomeArquivo) { ...

extends Angu { // quer aproveitar cdigo de Angu

Um Exemplo de Refatoramento
Como programador, voc precisa treinar seu nariz para detectar "mau cheiro" em cdigo Veremos um exemplo disso agora Melhoraremos o programa atravs de refatoramento Refatoramento alterar um programa mas sem afetar a funcionalidade que ele oferece Nosso exemplo pequeno devido a restries de tempo, mas imagine o que ocorreria se um cdigo grande fosse
9 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

to mal feito quanto o que veremos agora Refatoramento sempre deve ser feito apoiando-se em Testes de Unidade para assegurar-se de que as transformaes no cdigo no quebrem cdigo que funciona No mostraremos os testes de unidade aqui por questo de tempo

O Programa Original
O programa simples: ele calcula e emite um extrato de um cliente numa vdeo-locadora Vamos executar o programa para ver uma sada possvel:
C:\...\locadora-v1>java Locadora Registro de Alugueis de Juliana O Exorcista 3.5 Men in Black 2.0 Jurassic Park III 9.0 Planeta dos Macacos 12.0 Pateta no Planeta dos Macacos 12.0 O Rei Leao 42.0 Valor total devido: 80.5 Voce acumulou 8 pontos de alugador frequente

Eis o diagrama UML das classes principais

10 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

A classe Fita usada apenas para conter os atributos (locadora-v1\Fita.java)


public class Fita { public static final int NORMAL = 0; public static final int LANAMENTO = 1; public static final int INFANTIL = 2; private String ttulo; private int cdigoDePreo; public Fita(String ttulo, int cdigoDePreo) { this.ttulo = ttulo; this.cdigoDePreo = cdigoDePreo; } public String getTtulo() { return ttulo; } public int getCdigoDePreo() { return cdigoDePreo; } public void setCdigoDePreo(int cdigoDePreo) { this.cdigoDePreo = cdigoDePreo; } }

11 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

A classe Aluguel representa o aluguel de uma fita por um certo nmero de dias (locadora-v1\Aluguel.java)
public class Aluguel { private Fita fita; private int diasAlugada; public Aluguel(Fita fita, int diasAlugada) { this.fita = fita; this.diasAlugada = diasAlugada; } public Fita getFita() { return fita; } public int getDiasAlugada() { return diasAlugada; } }

A classe Cliente representa um fregus da locadora de vdeo (locadora-v1\Cliente.java)


import java.util.*; public class Cliente { private String nome; private Collection fitasAlugadas = new Vector(); public Cliente(String nome) { this.nome = nome; } public String getNome() { return nome; } public void adicionaAluguel(Aluguel aluguel) { fitasAlugadas.add(aluguel); } public String extrato() { final String fimDeLinha = System.getProperty("line.separator"); double valorTotal = 0.0; int pontosDeAlugadorFrequente = 0;

12 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Iterator alugueis = fitasAlugadas.iterator(); String resultado = "Registro de Alugueis de " + getNome() + fimDeLin while(alugueis.hasNext()) { double valorCorrente = 0.0; Aluguel cada = (Aluguel)alugueis.next();

// determina valores para cada linha switch(cada.getFita().getCdigoDePreo()) { case Fita.NORMAL: valorCorrente += 2; if(cada.getDiasAlugada() > 2) { valorCorrente += (cada.getDiasAlugada() - 2) * 1.5; } break; case Fita.LANAMENTO: valorCorrente += cada.getDiasAlugada() * 3; break; case Fita.INFANTIL: valorCorrente += 1.5; if(cada.getDiasAlugada() > 3) { valorCorrente += (cada.getDiasAlugada() - 3) * 1.5; } break; } //switch // trata de pontos de alugador frequente pontosDeAlugadorFrequente++; // adiciona bonus para aluguel de um lanamento por pelo menos 2 d if(cada.getFita().getCdigoDePreo() == Fita.LANAMENTO && cada.getDiasAlugada() > 1) { pontosDeAlugadorFrequente++; }

// mostra valores para este aluguel resultado += "\t" + cada.getFita().getTtulo() + "\t" + valorCorre valorTotal += valorCorrente; } // while // adiciona rodap resultado += "Valor total devido: " + valorTotal + fimDeLinha; resultado += "Voce acumulou " + pontosDeAlugadorFrequente + " pontos de alugador frequente"; return resultado; } }

Finalmente, a classe Locadora exercita o programa:

13 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

public class Locadora { public static void main(String[] args) { Cliente c1 = new Cliente("Juliana"); c1.adicionaAluguel(new c1.adicionaAluguel(new c1.adicionaAluguel(new c1.adicionaAluguel(new c1.adicionaAluguel(new c1.adicionaAluguel(new Aluguel(new Aluguel(new Aluguel(new Aluguel(new Aluguel(new Aluguel(new

Fita("O Exorcista Fita("Men in Black Fita("Jurassic Park III Fita("Planeta dos Macacos Fita("Pateta no Planeta dos Macac Fita("O Rei Leao

System.out.println(c1.extrato()); } }

Comentrios sobre o Programa Original


O programa no est bem projetado e no "orientado a objeto" O mau cheiro que indica isso : O mtodo extrato() muito grande e faz tudo sozinho No h responsabilidades assumidas pelas classes Fita e Aluguel Mas o que importa isso se o programa funciona? Cdigo ruim difcil de alterar Se difcil, ento bugs sero introduzidos Exemplo: o que deve ser mudado para ter um extrato em HTML? Nada pode ser reusado! Um novo mtodo inteiro deve ser escrito, sem aproveitar cdigo existente Claro que voc pode resolver isso com "cut-andpaste" Mas o que ocorre se as regras de preos mudarem? Vai ter que alterar cdigo em dois lugares Outro exemplo: a classificao em 3 tipos de fitas vai mudar mas os donos da locadora no sabem exatamente o que querem ainda e voc pode ter certeza que haver vrias mudanas ao longo do
14 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

tempo Nosso cdigo est pronto para lidar facilmente com um novo esquema de classificao de fitas? No. Nosso cdigo est pronto para lidar facilmente com um novo esquema de pontos de alugador frequente? No.

Refatoramento: Decomposio e Redistribuio do mtodo extrato()


Antes de continuar, repetimos: Para refatorar, voc precisa ter testes automticos Vamos supor que eles existam (no os veremos por questo de tempo) Ataquemos o primeiro problema: o mtodo extrato() muito grande e "faz tudo sozinho" Vamos decompor este mtodo em pedaos menores Vamos pegar um bloco de cdigo com alguma coeso e vamos extrair e coloc-lo num mtodo Qual bloco escolher? A experincia importante aqui mas tambm lembre a regra sobre Alta Coeso O switch o clculo de valorCorrente para uma fita e parece um pedao coeso que merece um mtodo parte Teste de coeso: O trabalho que o mtodo faz pode ser dito numa frase curta? Se puder, um bom mtodo a ser criado Aqui, podemos dizer que o bloco extrado "calcula o preo de aluguel de uma fita" Parece coeso Segue o csigo antes e depois do refatoramento, com o azul indicando as mudanas Antes
public String extrato() { final String fimDeLinha = System.getProperty("line.separator");

15 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

double valorTotal = 0.0; int pontosDeAlugadorFrequente = 0; Iterator alugueis = fitasAlugadas.iterator(); String resultado = "Registro de Alugueis de " + getNome() + fimDeLin while(alugueis.hasNext()) { double valorCorrente = 0.0; Aluguel cada = (Aluguel)alugueis.next();

// determina valores para cada linha switch(cada.getFita().getCdigoDePreo()) { case Fita.NORMAL: valorCorrente += 2; if(cada.getDiasAlugada() > 2) { valorCorrente += (cada.getDiasAlugada() - 2) * 1.5; } break; case Fita.LANAMENTO: valorCorrente += cada.getDiasAlugada() * 3; break; case Fita.INFANTIL: valorCorrente += 1.5; if(cada.getDiasAlugada() > 3) { valorCorrente += (cada.getDiasAlugada() - 3) * 1.5; } break; } //switch // trata de pontos de alugador frequente pontosDeAlugadorFrequente++; // adiciona bonus para aluguel de um lanamento por pelo menos 2 d if(cada.getFita().getCdigoDePreo() == Fita.LANAMENTO && cada.getDiasAlugada() > 1) { pontosDeAlugadorFrequente++; }

// mostra valores para este aluguel resultado += "\t" + cada.getFita().getTtulo() + "\t" + valorCorre valorTotal += valorCorrente; } // while // adiciona rodap resultado += "Valor total devido: " + valorTotal + fimDeLinha; resultado += "Voce acumulou " + pontosDeAlugadorFrequente + " pontos de alugador frequente"; return resultado; }

Depois
16 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

public String extrato() { final String fimDeLinha = System.getProperty("line.separator"); double valorTotal = 0.0; int pontosDeAlugadorFrequente = 0; Iterator alugueis = fitasAlugadas.iterator(); String resultado = "Registro de Alugueis de " + getNome() + fimDeLin while(alugueis.hasNext()) { Aluguel cada = (Aluguel)alugueis.next(); valorCorrente = valorDeUmAluguel(cada);

// trata de pontos de alugador frequente pontosDeAlugadorFrequente++; // adiciona bonus para aluguel de um lanamento por pelo menos 2 d if(cada.getFita().getCdigoDePreo() == Fita.LANAMENTO && cada.getDiasAlugada() > 1) { pontosDeAlugadorFrequente++; }

// mostra valores para este aluguel resultado += "\t" + cada.getFita().getTtulo() + "\t" + valorCorre valorTotal += valorCorrente; } // while // adiciona rodap resultado += "Valor total devido: " + valorTotal + fimDeLinha; resultado += "Voce acumulou " + pontosDeAlugadorFrequente + " pontos de alugador frequente"; return resultado; } private int valorDeUmAluguel(Aluguel cada) { int valorCorrente = 0; // determina valores para cada linha switch(cada.getFita().getCdigoDePreo()) { case Fita.NORMAL: valorCorrente += 2; if(cada.getDiasAlugada() > 2) { valorCorrente += (cada.getDiasAlugada() - 2) * 1.5; } break; case Fita.LANAMENTO: valorCorrente += cada.getDiasAlugada() * 3; break; case Fita.INFANTIL: valorCorrente += 1.5; if(cada.getDiasAlugada() > 3) { valorCorrente += (cada.getDiasAlugada() - 3) * 1.5;

17 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

} break; } //switch return valorCorrente; }

Depois de uma mudana dessas, compilamos e testamos para verificar que no quebramos nada Ao testar, verificamos que vrios testes falham! Examinando os testes que falharam e o cdigo, observamos logo que usamos "int" em vez de "double" Da a importncia de sempre ter testes para refatorar O mtodo mudado para a verso seguinte:
private double valorDeUmAluguel(Aluguel cada) { double valorCorrente = 0; // determina valores para cada linha switch(cada.getFita().getCdigoDePreo()) { case Fita.NORMAL: valorCorrente += 2; if(cada.getDiasAlugada() > 2) { valorCorrente += (cada.getDiasAlugada() - 2) * 1.5; } break; case Fita.LANAMENTO: valorCorrente += cada.getDiasAlugada() * 3; break; case Fita.INFANTIL: valorCorrente += 1.5; if(cada.getDiasAlugada() > 3) { valorCorrente += (cada.getDiasAlugada() - 3) * 1.5; } break; } //switch return valorCorrente; }

Separamos o mtodo grande em dois Agora podemos continuar a trabalhar em cada pedao individualmente Princpio da Diviso-e-Conquista para lidar com a complexidade
18 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Vamos fazer uma mudana pequena no mtodo valorDeAluguel Algumas variveis vo mudar de nome
private double valorDeUmAluguel(Aluguel umAluguel) { double valorDoAluguel = 0; // determina valores para cada linha switch(umAluguel.getFita().getCdigoDePreo()) { case Fita.NORMAL: valorDoAluguel += 2; if(umAluguel.getDiasAlugada() > 2) { valorDoAluguel += (umAluguel.getDiasAlugada() - 2) * 1.5; } break; case Fita.LANAMENTO: valorDoAluguel += umAluguel.getDiasAlugada() * 3; break; case Fita.INFANTIL: valorDoAluguel += 1.5; if(umAluguel.getDiasAlugada() > 3) { valorDoAluguel += (umAluguel.getDiasAlugada() - 3) * 1.5; } break; } //switch return valorDoAluguel; }

Vale a pena mudar nomes de variveis assim? Claro! O cdigo deve comunicar bem seu propsito para outros programadores Nomes de variveis so um meio bsico de comunicao Qualquer idiota pode escrever cdigo que um computador entende. Bons programadores escrevem cdigo que um ser humano pode entender. Refatoramento: Movendo o Clculo de Valores Examine o cdigo do mtodo valorDeUmAluguel() O mtodo usa informao de um objeto da classe Aluguel mas nada usa do Cliente
19 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Pela regra de design "Colocar as Responsabilidades com os Dados", desconfiamos que o mtodo est na classe errada Vamos mover o mtodo para a classe Aluguel Cdigo antes:
class Cliente ... private double valorDeUmAluguel(Aluguel umAluguel) { double valorDoAluguel = 0; // determina valores para cada linha switch(umAluguel.getFita().getCdigoDePreo()) { case Fita.NORMAL: valorDoAluguel += 2; if(umAluguel.getDiasAlugada() > 2) { valorDoAluguel += (umAluguel.getDiasAlugada() - 2) * 1.5; } break; case Fita.LANAMENTO: valorDoAluguel += umAluguel.getDiasAlugada() * 3; break; case Fita.INFANTIL: valorDoAluguel += 1.5; if(umAluguel.getDiasAlugada() > 3) { valorDoAluguel += (umAluguel.getDiasAlugada() - 3) * 1.5; } break; } //switch return valorDoAluguel; }

Cdigo depois

class Aluguel ... double getValorDoAluguel() { // observe que o parmetro umAluguel sumi double valorDoAluguel = 0; // determina valores para cada linha switch(getFita().getCdigoDePreo()) { case Fita.NORMAL: valorDoAluguel += 2; if(getDiasAlugada() > 2) { valorDoAluguel += (getDiasAlugada() - 2) * 1.5; } break; case Fita.LANAMENTO: valorDoAluguel += getDiasAlugada() * 3;

20 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

break; case Fita.INFANTIL: valorDoAluguel += 1.5; if(getDiasAlugada() > 3) { valorDoAluguel += (getDiasAlugada() - 3) * 1.5; } break; } //switch return valorDoAluguel; } class Cliente ... private double valorDeUmAluguel(Aluguel umAluguel) { return umAluguel.getValorDoAluguel(); }

No cdigo acima, observe como delegamos em Cliente.valorDeUmAluguel Fizemos isso para fazer pequenas mudanas de cada vez ao refatorar Depois de testar, podemos remover o mtodo valorDeUmAluguel e chamar getValorDoAluguel() diretamente Cdigo antes
class Cliente ... ... valorCorrente = valorDeUmAluguel(cada); ...

Cdigo depois
class Cliente ... ... valorCorrente = cada.getValorDoAluguel(); ...

Isso parece muito mais orientado a objeto! A classe correta (Aluguel) assumiu a responsabilidade de calcular o preo do aluguel O prximo passo pode ser a remoo de variveis temporrias desnecessrias

21 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Exemplo: valorCorrente em extrato() Variveis a menos so coisas a menos para dar errado, no ter valor correto, no ser inicializada, etc. Cdigo antes

public String extrato() { final String fimDeLinha = System.getProperty("line.separator"); double valorTotal = 0.0; int pontosDeAlugadorFrequente = 0; Iterator alugueis = fitasAlugadas.iterator(); String resultado = "Registro de Alugueis de " + getNome() + fimDeLin while(alugueis.hasNext()) { Aluguel cada = (Aluguel)alugueis.next(); valorCorrente = valorDeUmAluguel(cada);

// trata de pontos de alugador frequente pontosDeAlugadorFrequente++; // adiciona bonus para aluguel de um lanamento por pelo menos 2 d if(cada.getFita().getCdigoDePreo() == Fita.LANAMENTO && cada.getDiasAlugada() > 1) { pontosDeAlugadorFrequente++; }

// mostra valores para este aluguel resultado += "\t" + cada.getFita().getTtulo() + "\t" + valorCorre valorTotal += valorCorrente; } // while // adiciona rodap resultado += "Valor total devido: " + valorTotal + fimDeLinha; resultado += "Voce acumulou " + pontosDeAlugadorFrequente + " pontos de alugador frequente"; return resultado; }

Cdigo depois

public String extrato() { final String fimDeLinha = System.getProperty("line.separator"); double valorTotal = 0.0; int pontosDeAlugadorFrequente = 0; Iterator alugueis = fitasAlugadas.iterator(); String resultado = "Registro de Alugueis de " + getNome() + fimDeLin while(alugueis.hasNext()) {

22 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Aluguel cada = (Aluguel)alugueis.next();

// trata de pontos de alugador frequente pontosDeAlugadorFrequente++; // adiciona bonus para aluguel de um lanamento por pelo menos 2 d if(cada.getFita().getCdigoDePreo() == Fita.LANAMENTO && cada.getDiasAlugada() > 1) { pontosDeAlugadorFrequente++; } // mostra valores para este aluguel resultado += "\t" + cada.getFita().getTtulo() + "\t" + cada.getValorDoAluguel() + fimDeLinha; valorTotal += cada.getValorDoAluguel(); } // while // adiciona rodap resultado += "Valor total devido: " + valorTotal + fimDeLinha; resultado += "Voce acumulou " + pontosDeAlugadorFrequente + " pontos de alugador frequente"; return resultado; }

Claro que depois de cada mudana, compile e teste Refatoramento: Extrao de Pontos de Alugador Frequente O que fizemos com o valor do aluguel pode ser feito com o clculo dos pontos de alugador frequente (PAF) Quem deve ter a responsabilidade de calcular os PAF? O clculo depende de informao que Aluguel conhece Deixe portanto o clculo na classe Aluguel Cdigo antes:

public String extrato() { final String fimDeLinha = System.getProperty("line.separator"); double valorTotal = 0.0; int pontosDeAlugadorFrequente = 0; Iterator alugueis = fitasAlugadas.iterator(); String resultado = "Registro de Alugueis de " + getNome() + fimDeLin while(alugueis.hasNext()) { Aluguel cada = (Aluguel)alugueis.next();

23 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

// trata de pontos de alugador frequente pontosDeAlugadorFrequente++; // adiciona bonus para aluguel de um lanamento por pelo menos 2 d if(cada.getFita().getCdigoDePreo() == Fita.LANAMENTO && cada.getDiasAlugada() > 1) { pontosDeAlugadorFrequente++; } // mostra valores para este aluguel resultado += "\t" + cada.getFita().getTtulo() + "\t" + cada.getValorDoAluguel() + fimDeLinha; valorTotal += cada.getValorDoAluguel(); } // while // adiciona rodap resultado += "Valor total devido: " + valorTotal + fimDeLinha; resultado += "Voce acumulou " + pontosDeAlugadorFrequente + " pontos de alugador frequente"; return resultado; }

Cdigo depois:

class Cliente ... public String extrato() { final String fimDeLinha = System.getProperty("line.separator"); double valorTotal = 0.0; int pontosDeAlugadorFrequente = 0; Iterator alugueis = fitasAlugadas.iterator(); String resultado = "Registro de Alugueis de " + getNome() + fimDeLin while(alugueis.hasNext()) { Aluguel cada = (Aluguel)alugueis.next(); pontosDeAlugadorFrequente += cada.getPontosDeAlugadorFrequente(); // mostra valores para este aluguel resultado += "\t" + cada.getFita().getTtulo() + "\t" + cada.getValorDoAluguel() + fimDeLinha; valorTotal += cada.getValorDoAluguel(); } // while // adiciona rodap resultado += "Valor total devido: " + valorTotal + fimDeLinha; resultado += "Voce acumulou " + pontosDeAlugadorFrequente + " pontos de alugador frequente"; return resultado; } class Aluguel ...

24 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

int getPontosDeAlugadorFrequente() { if(getFita().getCdigoDePreo() == Fita.LANAMENTO && getDiasAlugada return 2; } else { return 1; } }

Refatoramento: Remoo de Variveis Temporrias Mais uma vez, vamos falar de variveis temporrias Embora elas possam ser teis, elas frequentemente so indicativos de "mau cheiro" Examine, por exemplo, a varivel valorTotal Ela usada para calcular o valor total do extrato enquanto estamos no loop Na realidade, o loop est servindo para trs coisas: Montar o String do extrato Calcular o valor total Calcular os FAP Porm, esse trabalho talvez seja necessrio em outro lugar Por exemplo, posso querer saber o valor total em outro mtodo (extratoHTML()) e terei portanto que repetir o clculo do preo total neste lugar Faz sentido criarmos um mtodo getValorTotal()? Este mtodo faz algo que podemos resumir em uma frase curta? Sim! Portanto, crie o mtodo O mesmo pode ser dito sobre a varivel temporria pontosDeAlugadorFrequente Seria melhor criar um mtodo getPontosDeAlugadorFrequente() Embora esses dois passos devam ser feitos separadamente com testes a cada passo, vamos logo ver o resultado dos dois passos Cdigo antes:
25 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

class Cliente ... public String extrato() { final String fimDeLinha = System.getProperty("line.separator"); double valorTotal = 0.0; int pontosDeAlugadorFrequente = 0; Iterator alugueis = fitasAlugadas.iterator(); String resultado = "Registro de Alugueis de " + getNome() + fimDeLin while(alugueis.hasNext()) { Aluguel cada = (Aluguel)alugueis.next(); pontosDeAlugadorFrequente += cada.getPontosDeAlugadorFrequente(); // mostra valores para este aluguel resultado += "\t" + cada.getFita().getTtulo() + "\t" + cada.getValorDoAluguel() + fimDeLinha; valorTotal += cada.getValorDoAluguel(); } // while // adiciona rodap resultado += "Valor total devido: " + valorTotal + fimDeLinha; resultado += "Voce acumulou " + pontosDeAlugadorFrequente + " pontos de alugador frequente"; return resultado; }

Cdigo depois:

class Cliente ... public String extrato() { final String fimDeLinha = System.getProperty("line.separator"); Iterator alugueis = fitasAlugadas.iterator(); String resultado = "Registro de Alugueis de " + getNome() + fimDeLin while(alugueis.hasNext()) { Aluguel cada = (Aluguel)alugueis.next();

// mostra valores para este aluguel resultado += "\t" + cada.getFita().getTtulo() + "\t" + cada.getValorDoAluguel() + fimDeLinha; } // while // adiciona rodap resultado += "Valor total devido: " + getValorTotal() + fimDeLinha; resultado += "Voce acumulou " + getPontosTotaisDeAlugadorFrequente() " pontos de alugador frequente"; return resultado; } private double getValorTotal() { double valorTotal = 0.0;

26 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Iterator alugueis = fitasAlugadas.iterator(); while(alugueis.hasNext()) { Aluguel cada = (Aluguel)alugueis.next(); valorTotal += cada.getValorDoAluguel(); } return valorTotal; } private int getPontosTotaisDeAlugadorFrequente() { int pontos = 0; Iterator alugueis = fitasAlugadas.iterator(); while(alugueis.hasNext()) { Aluguel cada = (Aluguel)alugueis.next(); pontos += cada.getPontosDeAlugadorFrequente(); } return pontos; }

Pare a! Acabamos de deixar o cdigo maior com a ltima mudana! Valeu a pena? Sim! Motivos: Criamos dois mtodos teis que podero ser usados mais na frente Eles podero at ser tornados pblicos se for necessrio que entrem na interface da classe Organizamos o cdigo melhor onde cada pedacinho mais simples de entender Compare o mtodo original extrato() com a ltima verso E quanto ao desempenho?? Temos mais loops do que antes! possvel que haja um problema de desempenho mas s saberemos isso com um perfil de execuo Neste caso, numa aplicao de locadora de vdeo onde clientes alugam poucas fitas, eu garanto que o desempenho no ser afetado Os loops adicionais vo adicionar alguns milissegundos ao processamento
27 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Mas quanto tempo demora para imprimir o extrato em papel?!!? Agora podemos ver como fcil criar um extrato em HTML devido existncia dos dois mtodos teis que criamos
class Cliente ... public String extratoHTML() { Iterator alugueis = fitasAlugadas.iterator(); String resultado = "<H1>Registro de Alugueis de <EM>" + getNome() + "</EM></H1><P>\n"; while(alugueis.hasNext()) { Aluguel cada = (Aluguel)alugueis.next();

// mostra valores para este aluguel resultado += cada.getFita().getTtulo() + ": " + cada.getValorDoAluguel() + "<BR>\n"; } // while // adiciona rodap resultado += "<P>Valor total devido: <EM>" + getValorTotal() + "</EM resultado += "<P>Voce acumulou <EM>" + getPontosTotaisDeAlugadorFreq "</EM> pontos de alugador frequente"; return resultado; }

Refatoramento: Responsabilidades onde esto os dados


O switch est com problemas Ao ver um switch, verifique se o teste est sendo feito em cima dos seus prprios dados ou em cima dos dados de outro objeto Aqui, vemos que o Aluguel faz um switch em cima de dados da Fita! Portanto, faz mais sentido mover o mtodo getValorDoAluguel() para a classe Fita Cdigo antes:
class Aluguel ... double getValorDoAluguel() { double valorDoAluguel = 0; // determina valores para cada linha

28 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

switch(getFita().getCdigoDePreo()) { case Fita.NORMAL: valorDoAluguel += 2; if(getDiasAlugada() > 2) { valorDoAluguel += (getDiasAlugada() - 2) * 1.5; } break; case Fita.LANAMENTO: valorDoAluguel += getDiasAlugada() * 3; break; case Fita.INFANTIL: valorDoAluguel += 1.5; if(getDiasAlugada() > 3) { valorDoAluguel += (getDiasAlugada() - 3) * 1.5; } break; } //switch return valorDoAluguel; }

Cdigo depois:
class Aluguel ... double getValorDoAluguel() { return fita.getValorDoAluguel(diasAlugada); } } class Fita ... double getValorDoAluguel(int diasAlugada) { double valorDoAluguel = 0; switch(getCdigoDePreo()) { case NORMAL: valorDoAluguel += 2; if(diasAlugada > 2) { valorDoAluguel += (diasAlugada - 2) * 1.5; } break; case LANAMENTO: valorDoAluguel += diasAlugada * 3; break; case INFANTIL: valorDoAluguel += 1.5; if(diasAlugada > 3) { valorDoAluguel += (diasAlugada - 3) * 1.5; }

29 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

break; } //switch return valorDoAluguel; } }

Podemos fazer o mesmo com o clculo de PAF: Cdigo antes:

class Aluguel ... int getPontosDeAlugadorFrequente() { if(getFita().getCdigoDePreo() == Fita.LANAMENTO && getDiasAlugada return 2; } else { return 1; } }

Cdigo depois:
class Aluguel ... int getPontosDeAlugadorFrequente() { return fita.getPontosDeAlugadorFrequente(diasAlugada); }

class Fita ... int getPontosDeAlugadorFrequente(int diasAlugada) { if(getCdigoDePreo() == LANAMENTO && diasAlugada > 1) { return 2; } else { return 1; } }

Refatoramento: Uso de Polimorfismo


Queremos um cdigo que permita facilmente adicionar novas classificaes de fitas Refatoramento: Interfaces Temos uma classe (Fita) que possui dois mtodos que tm comportamento diferente dependendo de algum
30 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

atributo do objeto Veja o switch de getValorDoAluguel() Veja o teste em getPontosDeAlugadorFrequente() Isso indicativo que o polimorfismo poderia limpar as coisas De fato, Fitas diferentes poderiam responder de forma diferente s duas perguntas getValorDoAluguel() e getPontosDeAlugadorFrequente() Podemos portanto ter polimorfismo em cima de tipos de Fitas Melhor ainda: queremos isolar dois mundos O mundo das coisas que podem ser alugadas (fitas, jogos, DVDs, ...) O mundo que usa tais coisas Usaremos uma interface para isolar esses dois mundos Vamos primeiro definir uma interface para a situao Chamaremos a interface de Alugavel Agora, sero Fitas, mas depois podero ser DVDs, jogos, etc. Cdigo antes:
public class Aluguel { private Fita fita; private int diasAlugada; public Aluguel(Fita fita, int diasAlugada) { this.fita = fita; this.diasAlugada = diasAlugada; } public Fita getFita() { return fita; } ... }

Cdigo depois:
interface Alugavel { String getTtulo(); double getValorDoAluguel(int diasAlugada);

31 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

int getPontosDeAlugadorFrequente(int diasAlugada); } class Fita implements Alugavel { ... } public class Aluguel { private Alugavel fita; private int diasAlugada; public Aluguel(Alugavel fita, int diasAlugada) { this.fita = fita; this.diasAlugada = diasAlugada; } public Alugavel getFita() { return fita; } ... }

Refatoramento: Herana Ainda no temos polimorfismo porque apenas uma classe implementa a interface Alugavel A primeira soluo que vem mente fazer como segue:

Mas isso no funciona porque uma fita pode mudar sua classificao durante sua vida

32 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

No podemos mudar a classe de um objeto durante sua vida Isso se chama de "mutao" e no deve ser feito! Como lidar com isso? Separe o que igual daquilo que muda Encapsule cada um em objetos diferentes Resultado:

Observe que cada fita agora ser composta de dois objetos: Um para a fita em si Um para a classificao da fita Falamos que est havendo composio de objetos Para implementar getvalorDoAluguel(), a Fita delega para o objeto de classificao Por que tudo isso melhor? A composio pode ser alterada em tempo de execuo Isto , a Fita recebe um novo objeto composto de Classificacao Isso faz com que a composio seja frequentemente superior herana
33 de 46 15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

A herana ainda ocorre, mas no no mundo das fitas, mas no mundo das classificaes Agora, vamos fazer isso accontecer no cdigo So 2 passos: Implementar a composio de objetos de forma a permitir a mudana dinmica do objeto de classificao Mover o mtodo getValorDoAluguel de Fita para Classificacao Substituir os testes (switch/if) com polimorfismo Faamos a primeira etapa Queremos que cada fita vire dois objetos: uma fita e uma classificao Por enquanto, o objeto Classificacao quem vai responder getCdigoDePreo() Est havendo delegao No quero que a interface externa mude para quem usa a classe Fita Portanto, quem cria o novo objeto a prpria classe Fita para esconder tudo Cdigo antes:
class Fita ... private int cdigoDePreo; public Fita(String ttulo, int cdigoDePreo) { this.ttulo = ttulo; this.cdigoDePreo = cdigoDePreo; } public int getCdigoDePreo() { return cdigoDePreo; } public void setCdigoDePreo(int cdigoDePreo) { this.cdigoDePreo = cdigoDePreo; }

Cdigo depois:
class Fita ...

34 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

private Classificacao classificao; public Fita(String ttulo, int cdigoDePreo) { this.ttulo = ttulo; setCdigoDePreo(cdigoDePreo); } public int getCdigoDePreo() { return classificao.getCdigoDePreo(); } public void setCdigoDePreo(int cdigoDePreo) { switch(cdigoDePreo) { case NORMAL: classificao = new ClassificacaoNormal(); break; case LANAMENTO: classificao = new ClassificacaoLancamento(); break; case INFANTIL: classificao = new ClassificacaoInfantil(); break; } } } public abstract class Classificacao { public abstract int getCdigoDePreo(); } public class ClassificacaoNormal extends Classificacao { public abstract int getCdigoDePreo() { return Fita.NORMAL; } } public class ClassificacaoLancamento extends Classificacao { public abstract int getCdigoDePreo() { return Fita.LANAMENTO; } } public class ClassificacaoInfantil extends Classificacao { public abstract int getCdigoDePreo() { return Fita.INFANTIL; }

35 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Observe que, em tempo de execuo, podemos mudar a classificao de uma fita Basta chamar setCdigoDePreo(), como antes Agora, podemos atacar a segunda etapa: Os objetos de classificao devem implementar getValorDoAluguel() e getPontosDeAlugadorFrequente() que esto em Fita Mais uma vez, teremos delegao> O objeto Fita delega para Classificacao o clculo de getValorDoAluguel() e getPontosDeAlugadorFrequente() Cdigo antes:
class Fita ... public double getValorDoAluguel(int diasAlugada) { double valorDoAluguel = 0; switch(getCdigoDePreo()) { case NORMAL: valorDoAluguel += 2; if(diasAlugada > 2) { valorDoAluguel += (diasAlugada - 2) * 1.5; } break; case LANAMENTO: valorDoAluguel += diasAlugada * 3; break; case INFANTIL: valorDoAluguel += 1.5; if(diasAlugada > 3) { valorDoAluguel += (diasAlugada - 3) * 1.5; } break; } //switch return valorDoAluguel; } }

Cdigo depois:

36 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

class Fita ... public double getValorDoAluguel(int diasAlugada) { return classificao.getValorDoAluguel(diasAlugada); } class Classificacao public double getValorDoAluguel(int diasAlugada) { double valorDoAluguel = 0; switch(getCdigoDePreo()) { case Fita.NORMAL: valorDoAluguel += 2; if(diasAlugada > 2) { valorDoAluguel += (diasAlugada - 2) * 1.5; } break; case Fita.LANAMENTO: valorDoAluguel += diasAlugada * 3; break; case Fita.INFANTIL: valorDoAluguel += 1.5; if(diasAlugada > 3) { valorDoAluguel += (diasAlugada - 3) * 1.5; } break; } //switch return valorDoAluguel; } }

Estamos prontos para a ltima etapa: introduzir o polimorfismo Implementamos os mtodos adequados nas classes de Classificacao Depois, o mtodo getValorDoAluguel() pode virar abstrato na classe Classificacao Cdigo antes:
class Classificacao public double getValorDoAluguel(int diasAlugada) { double valorDoAluguel = 0; switch(getCdigoDePreo()) { case Fita.NORMAL: valorDoAluguel += 2; if(diasAlugada > 2) {

37 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

valorDoAluguel += (diasAlugada - 2) * 1.5; } break; case Fita.LANAMENTO: valorDoAluguel += diasAlugada * 3; break; case Fita.INFANTIL: valorDoAluguel += 1.5; if(diasAlugada > 3) { valorDoAluguel += (diasAlugada - 3) * 1.5; } break; } //switch return valorDoAluguel; } }

Cdigo depois:
abstract class Classificacao abstract double getValorDoAluguel(int diasAlugada); class ClassificacaoNormal extends Classificacao { public double getValorDoAluguel(int diasAlugada) { double valorDoAluguel = 2; if(diasAlugada > 2) { valorDoAluguel += (diasAlugada - 2) * 1.5; } return valorDoAluguel; } } class ClassificacaoLancamento extends Classificacao { public double getValorDoAluguel(int diasAlugada) { return diasAlugada * 3; } } class ClassificacaoInfantil extends Classificacao { public double getValorDoAluguel(int diasAlugada) { double valorDoAluguel = 1.5; if(diasAlugada > 3) { valorDoAluguel += (diasAlugada - 3) * 1.5; } return valorDoAluguel; }

38 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

O mesmo pode ser feito com getPontosDeAlugadorFrequente() Valeu a pena tanto esforo para introduzir polimorfismo? Primeiramente, um bom programador j teria colocado polimorfismo desde o incio Segundo, valeu a pena sim: o cdigo muito mais simples de mudar quando houver um novo esquema de preos, por exemplo.

A soluo final
A estrutura final a seguinte:

39 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Um diagrama de sequncia (em UML) mostra as interaes entre objetos

40 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Agora, podemos ver o cdigo final Observe que a classe Locadora no mudou
public class Locadora { public static void main(String[] args) { Cliente c1 = new Cliente("Juliana"); c1.adicionaAluguel(new c1.adicionaAluguel(new c1.adicionaAluguel(new c1.adicionaAluguel(new c1.adicionaAluguel(new c1.adicionaAluguel(new Aluguel(new Aluguel(new Aluguel(new Aluguel(new Aluguel(new Aluguel(new

Fita("O Exorcista Fita("Men in Black Fita("Jurassic Park III Fita("Planeta dos Macacos Fita("Pateta no Planeta dos Macac Fita("O Rei Leao

System.out.println(c1.extrato()); } }

41 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

import java.util.*; public class Cliente { private String nome; private Collection fitasAlugadas = new Vector(); public Cliente(String nome) { this.nome = nome; } public String getNome() { return nome; } public void adicionaAluguel(Aluguel aluguel) { fitasAlugadas.add(aluguel); }

public String extrato() { final String fimDeLinha = System.getProperty("line.separator"); Iterator alugueis = fitasAlugadas.iterator(); String resultado = "Registro de Alugueis de " + getNome() + fimDeLin while(alugueis.hasNext()) { Aluguel cada = (Aluguel)alugueis.next();

// mostra valores para este aluguel resultado += "\t" + cada.getFita().getTtulo() + "\t" + cada.getValorDoAluguel() + fimDeLinha; } // while // adiciona rodap resultado += "Valor total devido: " + getValorTotal() + fimDeLinha; resultado += "Voce acumulou " + getPontosTotaisDeAlugadorFrequente() " pontos de alugador frequente"; return resultado; } private double getValorTotal() { double valorTotal = 0.0; Iterator alugueis = fitasAlugadas.iterator(); while(alugueis.hasNext()) { Aluguel cada = (Aluguel)alugueis.next(); valorTotal += cada.getValorDoAluguel(); } return valorTotal; }

42 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

private int getPontosTotaisDeAlugadorFrequente() { int pontos = 0; Iterator alugueis = fitasAlugadas.iterator(); while(alugueis.hasNext()) { Aluguel cada = (Aluguel)alugueis.next(); pontos += cada.getPontosDeAlugadorFrequente(); } return pontos; } }

public class Aluguel { private Alugavel fita; private int diasAlugada; public Aluguel(Alugavel fita, int diasAlugada) { this.fita = fita; this.diasAlugada = diasAlugada; } public Alugavel getFita() { return fita; } public int getDiasAlugada() { return diasAlugada; } double getValorDoAluguel() { return fita.getValorDoAluguel(diasAlugada); } int getPontosDeAlugadorFrequente() { return fita.getPontosDeAlugadorFrequente(diasAlugada); } }

interface Alugavel { String getTtulo(); double getValorDoAluguel(int diasAlugada); int getPontosDeAlugadorFrequente(int diasAlugada); }

43 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

public class Fita implements Alugavel { public static final int NORMAL = 0; public static final int LANAMENTO = 1; public static final int INFANTIL = 2; private String ttulo; private Classificacao classificao; public Fita(String ttulo, int cdigoDePreo) { this.ttulo = ttulo; setCdigoDePreo(cdigoDePreo); } public String getTtulo() { return ttulo; } public int getCdigoDePreo() { return classificao.getCdigoDePreo(); } public void setCdigoDePreo(int cdigoDePreo) { switch(cdigoDePreo) { case NORMAL: classificao = new ClassificacaoNormal(); break; case LANAMENTO: classificao = new ClassificacaoLancamento(); break; case INFANTIL: classificao = new ClassificacaoInfantil(); break; } } public double getValorDoAluguel(int diasAlugada) { return classificao.getValorDoAluguel(diasAlugada); } public int getPontosDeAlugadorFrequente(int diasAlugada) { return classificao.getPontosDeAlugadorFrequente(diasAlugada); } }

public abstract class Classificacao { abstract int getCdigoDePreo(); abstract double getValorDoAluguel(int diasAlugada);

44 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

int getPontosDeAlugadorFrequente(int diasAlugadas) { return 1; } } class ClassificacaoNormal extends Classificacao { int getCdigoDePreo() { return Fita.NORMAL; } double getValorDoAluguel(int diasAlugada) { double valorDoAluguel = 2; if(diasAlugada > 2) { valorDoAluguel += (diasAlugada - 2) * 1.5; } return valorDoAluguel; } } class ClassificacaoLancamento extends Classificacao { int getCdigoDePreo() { return Fita.LANAMENTO; } double getValorDoAluguel(int diasAlugada) { return diasAlugada * 3; } int getPontosDeAlugadorFrequente(int diasAlugadas) { return (diasAlugadas > 1) ? 2 : 1; } } class ClassificacaoInfantil extends Classificacao { int getCdigoDePreo() { return Fita.INFANTIL; } double getValorDoAluguel(int diasAlugada) { double valorDoAluguel = 1.5; if(diasAlugada > 3) { valorDoAluguel += (diasAlugada - 3) * 1.5; } return valorDoAluguel; }

45 de 46

15/6/2012 07:13

Orientao a Objeto - Regras Bsicas de Design

http://walfredo.dsc.ufcg.edu.br/cursos/2003/progII20031/aulas/design.htm

Palavras Finais
Uma faceta importante do refactoring o ritmo Testa, mude um pouco, testa, mude um pouco, ... Este ritmo permite fazer refatoramento de forma simples, rpida e segura
oo-9 programa anterior prxima

46 de 46

15/6/2012 07:13