Top Posts

Sobre o exame 310-055/SCJP

Continue lendo

Série DesignPattern: Visitor

Posted by camilolopes | Posted in DesignPattern, Series | Posted on 16-06-2012

0

Olá Pessoal,

Chegamos ao último post da Série DesignPattern. E hoje vamos conhecer o padrão de comportamento Visitor. Em resumo, o Visitor permite atualizarmos uma coleção de objetos de acordo com o tipo de cada objeto contido na coleção. Na prática você tem uma lista com vários objetos com tipos diferentes e cada um sofrerá um tipo de atualização. Neste post vamos ver isso, praticando com o conceito de contas bancárias.

Lets go…

Visitor

Permite atualizações específicas em uma coleção de objetos de acordo com o tipo particular de cada objeto.

Exemplo: posso ter uma lista de contas: poupança, corrente, digital etc. O banco pode querer atualizar a taxa para o valor X com base no tipo. Se for poupança, a taxa de rendimento será 0.5%, se for corrente será 0.0%. No diagrama a seguir temos uma ideia do Visitor. Fiz com base no nosso exemplo.

Praticando

A seguir teremos o projeto e a implementação. Como sempre, há comentários chamando atenção para o que considerei importante.  Crie um projeto conforme a imagem seguir:

Criando o Visitor AtualizadorConta (interface)

Primeiramente vamos criar o nosso Visitor, pois ele define os objetos responsáveis pelas atualizações:

package br.com.camilolopes.visitor;

import br.com.camilolopes.classes.ContaCorrente;

import br.com.camilolopes.classes.ContaPoupanca;

/*O tal do Visitor que define os objetos responsaveis

* pelas atualizações: Conta Corrente & Conta Poupança

*/

public interface AtualizadorConta {

void atualiza(ContaCorrente contaCorrente);

void atualiza(ContaPoupanca contaPoupanca);

}

Claro que ainda não temos as classes ContaCorrente e ContaPoupanca. Portanto, vamos criá-las em alguns minutos.  Mas antes precisamos criar a nossa classe abstract Conta e a interface Atualizável, que representa um Element, ou seja, sabemos os objetos que podem ser atualizados pelo Visitor.

Atualizavel.java (interface)

package br.com.camilolopes.interfaces;

import br.com.camilolopes.visitor.AtualizadorConta;

/*Element: interface que define os objetos que podem

* ser atualizados por um Visitor

*

*/

public interface Atualizavel {

void atualiza(AtualizadorConta atualizadorConta);

}

Conta.java

A classe Conta implementa a Interface Atualizável. Isso, lá na frente, vai evitar o uso de if/else encadeados para verificar o tipo. Você vai ver que não temos if/else no nosso código, tudo é baseado no tipo do objeto. Muito show!!!

package br.com.camilolopes.classes;

import br.com.camilolopes.interfaces.Atualizavel;

publicabstractclass Conta implements Atualizavel {

privatedouble saldo;

public Conta(double saldo) {

this.saldo = saldo;

}

publicdouble getSaldo() {

return saldo;

}

publicvoid setSaldo(double saldo) {

this.saldo = saldo;

}

}

ContaCorrente.java

package br.com.camilolopes.classes;

import br.com.camilolopes.visitor.AtualizadorConta;

public class ContaCorrente extends Conta{

private double saldo;

public ContaCorrente(double saldo) {

super(saldo);

this.saldo = saldo;

}

public void setSaldo(double saldo) {

this.saldo = saldo;

}

public double getSaldo() {

return saldo;

}

@Override

public void atualiza(AtualizadorConta atualizadorConta) {

atualizadorConta.atualiza(this);

}

}

ContaPoupanca.java

package br.com.camilolopes.classes;

import br.com.camilolopes.visitor.AtualizadorConta;

public class ContaPoupanca extends Conta{

private double saldo;

public ContaPoupanca(double saldo) {

super(saldo);

this.saldo = saldo;

}

public void setSaldo(double saldo) {

this.saldo = saldo;

}

public double getSaldo() {

return saldo;

}

@Override

public void atualiza(AtualizadorConta atualizadorConta) {

atualizadorConta.atualiza(this);

}

}

Agora precisamos criar a classe que tem as contas, ou seja, um Banco tem N tipos de contas. Então criamos a nossa classe Banco responsável por ter as contas.

Banco.java

package br.com.camilolopes.classes;

import java.util.ArrayList;

import java.util.List;

import br.com.camilolopes.visitor.AtualizadorConta;

public class Banco {

private List<Conta> contas = new ArrayList<Conta>();

public List<Conta> getContas() {

return contas;

}

public void setContas(List<Conta> contas) {

this.contas = contas;

}

public void atualizando(AtualizadorConta atualizadorConta){

for (Conta conta :this.contas) {

/*aqui que tem a mágica

* chama a conta com base no tipo

* evitamos if/else encadeados

*/

conta.atualiza(atualizadorConta);

}

}

}

note: Observe que nossa lista é focada na classe abstract. Se amanhã surgir um novo tipo de conta, precisamos apenas informar ao Visitor o novo tipo de conta e o que ele precisa atualizar.

Pronto! Tudo já certinho. Vamos testar para ver se de fato as atualizações na coleção acontecem com base no tipo do objeto. Para isso criei uma classe com o método main:

VisitorMain.java

package br.com.camilolopes.main;

import java.util.ArrayList;

import java.util.List;

import br.com.camilolopes.classes.AtualizaConta;

import br.com.camilolopes.classes.Banco;

import br.com.camilolopes.classes.Conta;

import br.com.camilolopes.classes.ContaCorrente;

import br.com.camilolopes.classes.ContaPoupanca;

public class VisitorMain {

public static void main(String[] args) {

//lembre-se um banco tem N contas

List<Banco> lista = new ArrayList<Banco>();

//criando as contas

ContaCorrente contaCorrente = new ContaCorrente(100.00);

ContaPoupanca contaPoupanca = new ContaPoupanca(1000.00);

//criando o Banco

Banco bancoX = new Banco();

//adicionando as contas ao Banco

bancoX.getContas().add(contaPoupanca);

bancoX.getContas().add(contaCorrente);

lista.add(bancoX);

AtualizaConta atualizaConta = new AtualizaConta();

//atualizando as contas por Banco

for(Banco banco : lista){

banco.atualizando(atualizaConta);

}

//verificando atualização

for(Banco b :lista){

for(Conta c : b.getContas()){

System.out.println(c.getClass().getSimpleName() + ” ” + c.getSaldo());

}

}

}

}

Resultado

A seguir temos o resultado. Veja que os valores foram atualizados com base no cálculo:


GitHub

Os projetos Java da série estão no meu GitHub: https://github.com/camilolopes/workspacedesignpattern.git

Feito pessoal. Vou ficando por aqui… espero que vocês tenham gostado do post e da série DesignPattern.

Abracos, see ya!!

Série DesignPattern:State

Posted by camilolopes | Posted in DesignPattern, Series | Posted on 28-05-2012

2

Olá Pessoal,

No post de hoje vamos conhecer o design pattern chamado State. Em poucas palavras, ele é baseado no comportamento do objeto. Se o comportamento foi alterado para Y, então a forma de trabalho desse objeto é Y. Vamos ver colocando à mão na massa, acho que será mais produtivo.

Lets go…

Download dos projetos

https://github.com/camilolopes

State

É um padrão comportamental do design pattern. Este é focado em saber se o estado de um objeto foi alterado. Ou seja, o State permite alterar o comportamento de um objeto com base no estado atual.

Se o taxímetro é bandeira 1, o cálculo é feito de maneira X, com valores Y, mas se o estado atual saiu de bandeira 1 e foi para bandeira 2, o cálculo é feito de maneira  X com valor Z.

No diagrama que criei acima mostra como as classes se entendem.

Na Prática

Agora vamos conhecer praticando, e como sempre, código no modo didático para ajudar quem está vendo o assunto pela primeira vez. A seguir, nosso projeto:

Bandeira.java

Criaremos inicialmente a interface state, que é a Bandeira.

Bandeira.java

package br.com.camilolopes.interfaces.state;

public interface Bandeira {
    double calculoBandeira(double distancia);
}

As classes Bandeira 1, Bandeira2.java são classes  que implementam o State, ou seja, Bandeira 1 tem uma formula X de cálculo, a bandeira 2 também terá a forma dele calcular e assim sucessivamente.

package br.com.camilolopes.classes;
import br.com.camilolopes.interfaces.state.Bandeira;
public class Bandeira1 implements Bandeira {
    @Override
    public double calculoBandeira(double distancia) {        
        double total = distancia * 1.5 ;
        return total;
    }
}

Bandeira2.java

package br.com.camilolopes.classes;
import br.com.camilolopes.interfaces.state.Bandeira;
public class Bandeira2 implements Bandeira {
    @Override
    public double calculoBandeira(double distancia) {
        //não gosto muito desses number magic aqui, mas vou deixar por enquanto
        double total = distancia * 3.0 + 1.0;
        return total;
    }
}

Taximetro.java

package br.com.camilolopes.classes;
import br.com.camilolopes.interfaces.state.Bandeira;
/*
 * classe que mantem referencia para um State com base no estado atual
 */
public class Taximetro {
    /*um taximetro has-a bandeira
     * ou seja, para um taximetro ter vida
     * ele precisa estar associado com uma bandeira
     */
    private Bandeira bandeira;

    public Taximetro(Bandeira bandeira) {
        super();
        this.bandeira = bandeira;
    }

    public Bandeira getBandeira() {
        return bandeira;
    }

    public void setBandeira(Bandeira bandeira) {
        this.bandeira = bandeira;
    }
    //aqui o taximetro vai calcular c/ base no tipo de Bandeira
    public double calculaCorrida(double distancia){
        double totalCorrida = bandeira.calculoBandeira(distancia);
    return totalCorrida;
    }
}

Criamos o relacionamento entre o Taxímetro e a Bandeira, já que para o taxímetro existir precisa de uma bandeira.

TaximetroMain.java

import br.com.camilolopes.classes.Bandeira1;
import br.com.camilolopes.classes.Bandeira2;
import br.com.camilolopes.classes.Taximetro;

public class TaxiMain {

    public static void main(String[] args) {
        Bandeira1 bandeira1 = new Bandeira1();
        Taximetro taximetro = new Taximetro(bandeira1);
        taximetro.setBandeira(bandeira1);
        System.out.println(“Valor da corrida com bandeira 1: “+ taximetro.calculaCorrida(2.0));
        taximetro.setBandeira(new Bandeira2());
        System.out.println(“O valor da corrida com bandeira 2: ”    + taximetro.calculaCorrida(2.0));
    }
}

Feito isso, criamos uma classe main que vai nos ajudar a ver o resultado com base no tipo passado.

Resultado

A seguir temos o resultado com a Bandeira 1 e 2. Observe que a distância passada foi a mesma, porém o resultado diferente, já que cada Bandeira tem um cálculo específico e o nosso Taxímetro sabe o que mostrar com base no estado da Bandeira (1,2,3…)

E esse é o design pattern state. Vou ficando por aqui e até o próximo post.

See ya!!