Mostrando postagens com marcador aap. Mostrar todas as postagens
Mostrando postagens com marcador aap. Mostrar todas as postagens

quinta-feira, 25 de setembro de 2014

Nestas Eleições, escolha em sobrepor o toString!


Bom, garanto que você esta se questionando o porquê deste titulo bizarro. Tentarei esclarecer esta questão...

Ao contrario de muitos candidatos, o toString fará e mostrará o que você quer,(claro desde que seja programado para isto), mas se você não o sobrepor, ele só fará e mostrará o que já lhe vem programado a fazer, mostrará só um monte de coisas que você não entederá, códigos e símbolos muito estranhos, que vem da classe object.

Agora tentarei descrever de uma forma um pouco mais técnica o porquê se deve sempre sobrepor o toString.

Embora java.lang.Object forneça uma implementação do método toString, geralmente a string que ele retorna não é a que o usúario de sua classe vai querer ver. Ela é composta pelo nome da classe seguindo de uma "arroba(@)" e da representação do código de hash em hexadecimal sem sinal, por exemplo, "PhoneNumber@163b91". Ela deve ser uma representação concisa, mas não é tão facil de entender e ler se for comparado a "(53)3232-3232".

Fornecer uma boa implementação de toString tornará sua classe mais agradável de usar, o método toString é chamado automaticamente quando um objeto é passado para println, printf, para o operador de concatenação de strings ou para assert, ou exibido por um depurador. Para ser considerado prático, o método toString deve retornar todas as informações interessantes contidas no objeto, quando implementa-lo deve-se especificar o formato do valor de retorno na documentação.

A vantagem de especificar o formato é que ele serve como uma representação do objeto que é padrão, clara e legível por humanos.

A desvantagem de especificar o formato do valor de retorno, é que uma vez especificado você ficará preso a ele indefinidamente, supondo que sua classe seja muito usada. Se você alterar a representação em uma versão futura, invalidára seus códigos e dados e eles reclamarão.

Ao não especificar um formato, você preservará a flexiblidade de inclusão de informações ou aperfeiçoamento do formato em uma versão subsequente.

Decidindo ou não especificar o formato, não se esqueça em documentar claramente suas intenções.


Exemplo sem sobrepor o toString

public class Cliente {
    private String nome;
    public Cliente(String nome) {
        this.nome = nome;
    } 

     //@Override
     //public String toString() {   
     //return "O Melhor Jogador do TADS eh = " + nome;   
     //}

    public static void main(String[] args) {
        Cliente cliente = new Cliente("Falcãozinho Gaucho!");
        System.out.println(cliente);
    }
}

//Resposta com toString de Object (Cliente@1509443)


Exemplo sobrepondo o toString

public class Cliente {
    private String nome;
    public Cliente(String nome) {
        this.nome = nome;
    }     
     @Override
     public String toString() {   
     return "O Melhor Jogador do TADS eh = " + nome;   
     }
    public static void main(String[] args) {
        Cliente cliente = new Cliente("Falcãozinho Gaucho!");
        System.out.println(cliente);
    }
}


//Resposta com toString de sobrescrito (O Melhor Jogador do TADS eh = Falcãozinho Gaucho!)


Referência: Java Efetivo, de Joshua Bloch

Desenvolvimento e Otimização de um Projeto Baseados em Testes

Desenvolvimento e Otimização de um Projeto Baseados em Testes

O desenvolvimento baseado por testes deve seguir 3 regras simples:

  1. Não escrever o código de produção até que voce tenha escrito um teste de unidade que falhe.
  2. Não escrever mais um teste de unidade do que suficiente para falhar ou não compile.
  3. Não escrever mais que qualquer código de produção para passar no teste falho.

O objetivo é construir ciclos curtos, alternando as etapas de desenvolvimento. O conjunto de testes geram um impedimento para o desenvolvimento. Indica onde o programa apresenta falhas, nos permitindo criarmos funções para corrigir o programa ou para melhorarmos a sua eficiência.

Ao desenvolver um software baseado por testes ele deve ser desacoplado do seu ambiente para ser testado. Isso gera uma documentação importante para a empresa contratante e desenvolvedora.

Testes de Aceitação, além de necessários são fundamentais para que se verifique se os requisitos do cliente estão sendo cumpridos, mas são insuficientes como ferramentas de verificação do software.

Arquitetura do Projeto

Para desenvolver um projeto de software, é necessário ter uma equipe definida, com o modelo a seguir. Usando o modelo por testes pois como o programa de software a ser desenvolvido é de funções matemáticas, pode-se testa-lo desacoplado do seu ambiente e buscá-lo otimizá-lo.

A programação por pares pode ser uma excelente escolha, pois um programador desenvolve e o outro pode corrigir os erros e otimizar as funções do software.


                        +-------------+
                        | Matemática  |
                     1  | Aplicada    |
                        +-------------+             
         
     +-----------+      +-------------+    +-------------+
     | Algebra   |      | Geometria   |    | Estatística |
     +-----------+      +-------------+    +-------------+
  1A | Funções   |   1B |Trigonometria| 1C | Matemática  |
     | Calculos  |      |             |    | Financeira  |
     +-----------+      +-------------+    +-------------+
     
     
                        +-------------+
                        | Interface   |
                      2 | Usuário     |
                        +-------------+

Um exemplo de teste apresenta abaixo. Desenvolver funções matemáticas: O código mostra o código de números n primos, podendo ser implementados em linguagem Java, C ou C++.

Esse código quando o programador olha ele não sabe as funções de cada parâmetro e variável do código e tem que testa-lo, não sendo uma boa prática de programação.

 while(p>0)
 { 
  d=2;
  while((n%d)!=0)
  {
   d+=1;
  }
  if(d==n)
  { printf("n: %d ", n); 
   p--;
  }
  n++;
      
 }
 if (n==p)
 printf("n: %d ", n);

O código ao ser Testado mostra n números primos, em uma função desacoplada do projeto, mas pode ser refatorado e otimizado.

public int numeroPrimo() {
 for(primo=2; (numero>0);primo++)
 { for(quantidade=2;((p%quantidade)!=0);quantidade++)
  { if(d==p)
   { printf("primo: %quantidade ", primo); 
    numero--;
   }
  }
  if (quantidade == numero)
  printf("numero: %primo ", numero);
 }
 return numeroPrimo()
 }

O código refatorado apresenta uma maior otimização, o programador, ou equipe de desenvolvimento após testar o programa deve otimizar seu códigos usando refatoração ou outros métodos necessários conforme a plataforma utilizada ou a exigência da empresa, os nomes dos métodos e variáveis devem ser descritos na forma que qualquer outro programador, desenvolvedor veja o código fonte e entenda o programa. Sendo que implantado através de métodos permite a utilização através da chamada de métodos, sem repetir códigos e utilizá-lo em partes posteriores do projeto.

Obedecendo o novo paradigma que é a orientação orientada a objetos.

MARTIN. Micah, MARTIN Robert C.; Princípios, Padrões e Práticas Ágeis em C#. Editora Bookman,2011.

quinta-feira, 1 de maio de 2014

Padrão de Projeto Flyweight

O padrão de projeto Flyweight, ou "peso-mosca", é um padrão estrutural que tem por finalidade usar de compartilhamento de objetos de granularidade fina, isto é, objetos que são iguais exceto por pequenos detalhes. Este padrão usa as informações comuns a diversos objetos em apenas um componente, o resto dos dados únicos são utilizados como parâmetros de métodos, reduzindo o número de objetos em uma aplicação, e assim agilizando o processamento da execução destes muitos objetos repetidos.
Para um bom resultado do uso deste padrão,use-o quando todas as afirmativas seguintes forem verdadeiras:

- A aplicação usa um grande número de objetos;
- Custos de armazenamento são grandes por causa da grande quantidade de objetos;
- A maior parte do estado dos objetos podem ser extrínseco (informações que dependem e variam com o contexto do flyweight, e que por esse motivo nao podem ser compartilhados);
- Muitos grupos de objetos podem ser substituídos por poucos objetos que possam ser compartilhados (estado extrínseco deve ser removido para outro lugar);
- A aplicação não depende da identidade do objeto;

Ainda deve-se pensar sobre o ponto fraco do padrão, que é dependendo da quantidade e da organização dos objetos a serem compartilhados, pode haver um grande custo para procura deles. Então ao utilizar o padrão deve ser analisado qual a prioridade no projeto, espaço ou tempo de execução.
Os participantes deste padrão seriam:

- Cliente : computa ou armazena o estado extrínseco do flyweight, assim como mantém a referência para ele;
- Flyweight: declara uma interface por onde pode receber e atuar sobre estados extrínsecos;
- FlyweightFactory: cria e gerencia objetos flyweights e garante que eles sejam compartilhados corretamente. Quando um cliente solicita um flyweight, um objeto FlyweightFactory fornece a ele, ou cria se caso ele não exista.
- ConcretesFlyweights (no exemplo do processador de texto seria o caractere em si): implementa a interface Flyweight e armazena só os estados intrísecos (compartilháveis).

Um bom exemplo da utilização é no desenvolvimento de jogos, afinal são usadas várias imagens que representam as entidades que compõe o jogo (cenário, jogador, inimigo..).
Isso causa duplicação de informação.Por exemplo, quando aparecem vários inimigos iguais no jogo, o mesmo conjunto de imagens é criado repeditas vezes.
Para exemplificar isso em código, começamos criando uma classe Imagem (informação intríseco):
  public class Imagem {
    protected String NomedaImagem;

    public Imagem(String imagem) {
        NomedaImagem = imagem;
    }

    public void desenharImagem() {
      System.out.println(NomedaImagem + " desenhada!");
    }
    }

Entao criar a classe Ponto (informação extrínseco):
  public class Ponto {
    public int x, y;

    public Ponto(int x, int y) {
        this.x = x;
        this.y = y;
    }
    }
Uma classe Flyweight será feita para armazenar o método de desenho da imagem em um determinado ponto:
 public abstract class SpriteFlyweight {
    public abstract void desenharImagem(Ponto ponto);
    }
Após a criação da classe Flyweight, criamos uma classe Flyweight Concreta, que seria a implementação da operação de fato:
 public class Sprite extends SpriteFlyweight {
    protected Imagem imagem;

    public Sprite(String nomeDaImagem) {
        imagem = new Imagem(nomeDaImagem);
    }

    @Override
    public void desenharImagem(Ponto ponto) {
        imagem.desenharImagem();
        System.out.println("No ponto (" + ponto.x + "," + ponto.y + ")!");
    }
    }
  
A classe fábrica guardará todas as imagens que serão compartilhadas e terá um método para pega-las, tendo assim todo acesso as imagens centralizado nessa classe:
 public class FlyweightFactory {

    protected ArrayList flyweights;

    public enum Sprites {
        JOGADOR, INIMIGO_1, INIMIGO_2, CENARIO_1
    }

    public FlyweightFactory() {
        flyweights = new ArrayList();
        flyweights.add(new Sprite("jogador.png"));
        flyweights.add(new Sprite("inimigo1.png"));
        flyweights.add(new Sprite("inimigo2.png"));
        flyweights.add(new Sprite("cenario1.png"));
    }

    public SpriteFlyweight getFlyweight(Sprites jogador) {
        switch (jogador) {
        case JOGADOR:
            return flyweights.get(0);
        case INIMIGO_1:
            return flyweights.get(1);
        case INIMIGO_2:
            return flyweights.get(2);
        default:
            return flyweights.get(3);
        }
    }
    }
 
E utilizando esse padrão:
 public static void main(String[] args) {
    FlyweightFactory factory = new FlyweightFactory();

    factory.getFlyweight(Sprites.JOGADOR).desenharImagem(new Ponto(10, 10));

    factory.getFlyweight(Sprites.INIMIGO_1).desenharImagem(
            new Ponto(100, 10));
    factory.getFlyweight(Sprites.INIMIGO_1).desenharImagem(
            new Ponto(120, 10));
    factory.getFlyweight(Sprites.INIMIGO_1).desenharImagem(
            new Ponto(140, 10));
    factory.getFlyweight(Sprites.INIMIGO_2).desenharImagem(
            new Ponto(60, 10));
    factory.getFlyweight(Sprites.INIMIGO_2).desenharImagem(
            new Ponto(50, 10));
    }
Pode ser implementado algo para eliminar um objeto nao usado mais, liberando ele da memória e diminuindo espaço.

Referências :
Livro - Padroes de Projetos - Solucoes Reutilizaveis - Gamma Erich
Site - http://brizeno.wordpress.com/category/padroes-de-projeto/flyweight/

quarta-feira, 8 de janeiro de 2014

Data Binding

Olá, este post tem como função explicar o Data Binding, como usar e o por que. Então, lá vamos nós.

Data Binding é um processo que estabiliza uma conexão entre uma aplicação User Interface(JFrame) e a lógica do negócio. Se as configurações e notificações estiverem corretas, o Data Binding reflete as mudanças que elas fazem. Vamos supor que temos um AlunoFrame e nela um componente JTextField tNome, também temos a classe Aluno com o getNome e setNome. Se nós aplicarmos o Data Binding vamos fazer que quando seja digitado algo no TextField nome, automaticamente o setNome vai receber o que foi escrito, eles ficam sincronizados, as mudanças que ocorrem no nome ocorrem também no setNome e vice-versa. Mas então tu podes pensar, "por que não usar um setNome neste TextField?".

public class AlunoFrame extends javax.swing.JFrame{
     Aluno aluno = new Aluno();
     JTextField nome = new javax.swing.JTextField();
     /...

      private void tNomeActionPerformed(java.awt.event.ActionEvent evt){
         aluno.setNome(tNome.getText());         
     }

Podemos ver que fazendo assim não é nem um pouco elegante, deixamos o usuário com muita acessibilidade. Se por acaso ele quiser alterar para setMatricula ele pode, e não é isso que nós queremos. Nós temos que abstrair o usuário sobre o que está acontecendo. E também vale lembrar que para fazer espelhamento, deste modo fica muito "amador". Por isso vamos usar o Data Bindig, agora na prática vai ficar bem mais visível sua utilidade. Então vamos criar uma classe Bind que será a responsável por fazer a sincronização do JFrame com o negócio, so let's go.

public class Bind extends JTextField{    

    public Bind() {
        
    } 
    //criamos um método bind que vai receber os seguintes parametros
    //obj que será o objeto da classe que queremos alterar
    //atributo que será qual o atributo da classe que queremos mudar
    //campoFrame que é o que queremos onde a alteração seja feita
    //texto é a informação que vamos passar
    public void bind(Object obj, String atributo, Object campoFrame, String texto) throws NoSuchMethodException, IllegalAccessException...{

        //aqui nós vamos ver qual tipo é o campoFrame 
        //e depois repassamos para seu método correspondente
        if(campoFrame instanceof JTextField){
            JTextField tf = (JTextField) campoFrame;
            bindTextField(obj, atributo, tf, texto);
            return;
        }

        //exemplo com outros tipos de componentes
        if(campoFrame instanceof JComboBox){
            JComboBox cb = (JComboBox) campoFrame;
            bindComboBoxBinder(obj, atributo, cb, texto);            
            return;
        }
        if(campoFrame instanceof JRadioButton){
            JRadioButton rb = (JRadioButton) campoFrame;
            bindRadio(obj, atributo, rb, texto);
            return;
        }        
    }
Após implementar essa parte, nós precisamos fazer o bindTextField que terá como função ir lá no set da classe do objeto passado e alterar. Essa parte eu admito que é um pouco mais chatinha e complexa de entender pois vamos usar reflections e regex, então vou explicar por partes.

private void bindTextField(Object obj, String atributo, JTextField tf, String texto) throws NoSuchMethodException, IllegalAccessException... {
        tf.setText(texto);       
        
        //aqui nós vamos precisar usar reflections para saber os atributos
        //da classe do objeto que temos

        Field[] f = obj.getClass().getDeclaredFields(); //criamos um vetor de Field para pegar os atributos
        Field field = null; 
        
        //fazemos um for each para pesquisar dentro daquele nosso vetor 
        //para saber pegarmos o atributo que queremos alterar             
        for(Field campo : f){
            if(campo.getName().equals(atributo)){ //enquanto a variavel campo não for igual ao atributo continua o for
                field = campo; //a variavel field recebe o campo quando achado
                break;
            }
        }
        //agora que já achamos o atributo, nós precisamos encontrar o set dele
        //ATENÇÃO AGORA
        //Vamos criar uma String s que irá concatenar a palavra set com 
        //a primeira letra do atributo em maiuscula e o restante em minuscula
        String s = "set" + field.getName().toUpperCase().charAt(0)+ field.getName().substring(1);

        //no nosso exemplo fica s = "set"+N+ome
Depois que "formamos" o setNome, nós precisamos achar ele nos métodos da classe e fazer a alteração.
String tipo = field.getType().getSimpleName();//aqui criamos uma variavel tipo que irá
                                                      //pegar o nome do Tipo do campo field(que é nome)

        Method meth = null; //é criada uma variavel do tipo Method que será usada 
                            //para chegar ao método setNome
        
        //é feito um switch para ver qual é o Tipo do nosso atributo que será atualizado
        switch(tipo){
            case "String":
              //meth = aluno.getClass().getMethod(setNome, tipo String);
                meth = obj.getClass().getMethod(s, String.class);
                //usamos o metodo invoke para passar o objeto e a nova informação
                meth.invoke(obj, texto);
                break;
            case "int": case "Integer":
                meth = obj.getClass().getMethod(s,Integer.TYPE);
                meth.invoke(obj, Integer.parseInt(texto));
                break;
            case "float": case "Float": 
                meth = obj.getClass().getMethod(s,Float.TYPE);
                meth.invoke(obj, Float.parseFloat(texto));                
                break;
            case "double": case "Double":
                meth = obj.getClass().getMethod(s,Double.TYPE);
                meth.invoke(obj, Double.parseDouble(texto));  
                break;
            case "booelan": 
                Boolean.parseBoolean(texto);
                break;
            case "Date":
                 //OBSERVAÇÃO COM O DATE
                 //d{2}dias / d{2} mes / d{4} ano
                Pattern pattern = Pattern.compile("\\d{2}\\/\\d{2}\\/\\d{4}");
                        
                if(pattern.matcher(texto).find()){
                    SimpleDateFormat data = new SimpleDateFormat("dd/MM/yyyy");
                    meth = obj.getClass().getMethod(s, Date.class);
                    meth.invoke(obj, data.parse(texto));
                    
                }
                break;
        }       
    }
O case Date vou explicar por aqui pois é o mais complicado deles. Se por caso o nosso aluno tenha dataDeNascimento do tipo Date, vai ser necessário usar regex para formatar a data conforme for configurada pelo usuário, apartir do SimplesDateFormat(esqueçam todas gambiarras feitas até então). Criamos uma variável do tipo Pattern, quando colocamos o d{2} dizemos que aquela parte recebe até dois decimais. Mais a baixo temos um SimplesDateFormat que está separando por dia, mês e ano. Após isso, é igual aos outros.

Aqui terminamos nossa classe Bind, agora vamos ver como usar ela. No nosso formulário, no campo tNome nós precisamos usar o evento KeyReleased, fica da seguinte forma.

private void tNomeKeyReleased(java.awt.event.KeyEvent evt) {                                  
        Bind t = new Bind();
        t.bind(aluno2, "nome", tCampoParaMostrar, tNome.getText());
}

Admito que demorei para pegar a ideia do Data Binding, para entender como funciona essa sincronização via objeto, mas não é complicado de fazer, só é necessário tempo. Sobre reflections e regex, a ideia é bem fácil de entender.

terça-feira, 7 de janeiro de 2014

API Google Gson [JAVA SE7] Serializer and Deserializer Object

Neste post vou falar sobre a API Google Gson, desenvolvida pela google e disponibilizada gratuitamente neste link.
Esta API não tem muitos recursos, porém, é de grande importância ressaltar sua utilidade e rápida adaptação.

A Api do google gson, interpreta códigos enviados por arquivos Json ao software desenvolvido em JAVA e deserializa esses códigos para Classes java, instanciando assim: Objetos, classes, etc. Além disso, faz a engenharia reversa, onde recebe um objeto java e retorna um objeto JSON. Enfim, o uso dessa ferramente abre um leque de possibilidades dentro do java ao desenvolvedor, que pode usá-la para o que tiver necessidade em seu software.

Uma dica de uso é combinar esta biblioteca a uma já existente no Java SE7. A biblioteca java.lang.reflect.* na
qual você pode ler mais sobre clicando acima no link destacado.

Aqui irei demonstrar o uso da API para simples atribuição de Objetos, das duas formas.

lembrando que para usar o google Gson é necessário fazer o download da lib no site, e importá-lo no projeto corrente como biblioteca.

Exemplo1: 
    Neste caso, iremos serializar um Objeto Java, para transformá-lo num objeto Json.

Temos a classe Teste()
public class Teste {
    private String teste;
    private int numero;
    
    //+getters
    //+setter
    
    @Override
    public String toString() {
        return "teste = "+teste+" numero = "+numero;        
    }   
}

E temos a classe Principal TesteGson()
public class TesteGson {
    public static void main(String argumentos[]){
        Gson gson = new Gson();  //Instanciamos o uso do Gson
       
        Teste obj = new Teste("Gson", 1); // Criamos um obj do tipo Teste
        String s = gson.toJson(obj); //serializamos o obj
        System.out.println(s); //mostramos a string transformada em Json.
       
    }
   
}

Com este código temos a seguinte saída:
{"teste":"Gson","numero":1}

Exemplo 2:
  Neste exemplo iremos ver como Transformar um objeto Json em um Objeto Java. Vamos instanciar a mesma classe Teste() declarada acima.

Na janela Principal executaremos:
public class TesteGson {
    public static void main(String argumentos[]){
        Gson gson = new Gson();  //Instanciamos o uso do Gson
        
        String s = "{\"teste\":\"objectName\",\"numero\":2}";
        Teste obj = gson.fromJson(s, Teste.class);
        System.out.println(obj.toString());
    }
    
}

Com este código temos a seguinte saída:
teste = objectName numero = 2

Esta foi uma pequena introdução a API Google Gson, para saber mais sobre ela, consulte:
Google Gson 2.2.4 API.

Referências:
Google Gson User Guide.

Autor: Vinicius Montenegro.
    Graduando do Curso de Tecnologia em Análise e Desenvolvimento de Sistemas.
    FURG/IFRS - RIO GRANDE/RS.

segunda-feira, 30 de setembro de 2013

Desenvolvimento dirigido por testes

Desenvolvimento dirigido por testes

O Desenvolvimento dirigido por testes ou Test driven development (TDD) é uma técnica de desenvolvimento de software criada
por Kent Beck que e baseia em um ciclo curto de repetições.

O TDD tem uma idéia bem simples e um roteiro bem definido:

- Escreve um teste
- Roda o teste e ve ele falhar
- Escreve o código que deve passar no teste
- Roda o teste novamente esperando que ele passe (Se falhar, significa que há um problema com o código funcional)
- Refatora o código
- Roda o teste eo teste passa
- Começa com um teste diferente


Exemplo: Calculadora

- Criar classe TesteCalculadora e cria o método TestaAdicao

public class TesteCalculadora {
    public void TestaAdicao(){
        assertEquals("Resultado da soma de 3 e 4 é 7",7,Calculadora.soma(3,4));
    }
}
 

- Executar o teste e ter certeza de que ele irá falhar, afinal nem existe a classe Calculadora ou o método soma() ainda!

- Criar a classe Calculadora e o método soma

 public int soma (int a, int b){
  return a+b;
 }

- Executar o teste novamente e ver que ele nao irá falhar dessa vez.

- Analisar o código escrito por completo e verificar se há necessecidade de refatoração

- Executar todo o código para fins de teste novamente para nao ter dúvidas de não haver falhas

- Repitir o processo com um teste diferente!


Desenvolvimento dirigido por testes tem uma grande utilidade ajudando
a manter baixa a contagem de defeitos e mantendo a simplicidade do código.
Outra vantagem é que o TDD quando usado apropriadamente, garante que todo o código desenvolvido seja inteiramente testado. Isto fornece
a equipe de desenvolvimento, e ao usuários um grande nível de confiança ao código.


No TDD, os testes são de extrema importância e por isso devem ser bem escritos.


Um exemplo de um código ruim de teste, utilizando o exemplo anterior da calculadora:


 public void TestaAdicao(){
  assertEquals(3+4,Calculadora.soma(3,4));
 }
 

Se estamos testando o resultado do metodo soma, então precisamos saber o retorno. Nesse caso, melhor
escrever o código da seguinte forma:


 public void TestaAdicao(){
  assertEquals(7,Calculadora.soma(3,4));
 }
 

alguns pontos que devemos lembrar:

- Conseguir executar cada teste isoladamente
- Eliminar qualquer duplicação lógica dos testes
- Cada teste deve testar apenas um negócio
- Testar todas as pré-condições, pós-condições e exceções
- É também importante sempre escolher bons nomes para os métodos de teste,mesmo que fiquem longos

Não há nenhuma comprovação científica de que TDD melhore a qualidade do código ou a produtividade dos desenvolvedores mas existem
algumas evidências, eos relatos de inúmeras pessoas não nos deixam pensar de outra forma!


Referências:
Refatorações para Padrões do Joshua Kerievsky
Wikipedia Test Driven Developmen : http://pt.wikipedia.org/wiki/Test_Driven_Development

Padrão de Projeto Iterator

Padrão Iterator

        Imagine que você trabalha em uma rede de supermercado e tenha que mostrar uma lista de produtos, Refrigerante e Bolachas recheadas. Ai você descobre que a lista de refrigerantes foi criada utilizando Arraylist e os bolachas com Matriz.

Como mostrar ambos produtos? Apesar de ambos serem produtos cada um tem uma forma diferente de implementação.

Você não quer ou não pode padronizar a lista de produtos. Como conseguir mostrar uma lista que contenha ambos produtos?

Bom, poderia fazer um for para cada um e mostrar o produto pelo loop. Assim:

ArrayList<Produto> arrayListDeProdutos = new ArrayList<Produto>();
for (Produto produto : arrayListDeProdutos ) {
 System.out.println(produto.nome);
}

Produto[] matrizDeProdutos = new Produto[3];
for (int i = 0; i < matrizDeProdutos .length; i++) {
 System.out.println(matrizDeProdutos [i].nome);
}


É fácil perceber o problema dessa implantação sem ver o código, caso outra equipe armazene algum produto com outro tipo de estrutura, seria necessário mais um for.
E se precisar fazer alguma operação com a lista de produtos, terá de haver o mesmo método repetido para cada lista com estrutura diferente.

Ok, então vamos ver agora uma boa solução para esse problema.

Vamos conhecer o Padrão Iterator:

Conceito:
O Fornecer uma maneira de acessar sequencialmente os elementos
de um objeto agregado(coleção ou grupo de objetos) sem expor sua implementação.

A interface tem o método hasNext() que determina se há mais elementos no grupo para serem submetidos a iteração.

O método next() retorna o próximo objeto do grupo.

Obs: Quando falamos em coleção estamos nos referindo simplesmente a um grupo de objetos, mesmo que estejam armazenados em estruturas de dados muito diferentes como lista, matrizes hastable eles continuam formando uma coleção de objetos.

As vezes essas coleções são chamadas de Agregados.

A ideia do padrão Iterator é fornecer um meio eficiente de se percorrer todos os elementos de uma determinada coleção e de formas variadas.

O padrão propõe que se utilize uma interface para controlar a iteração. O objeto que implementar esta interface conhece a seqüência do grupo e mantém uma referencia ao elemento atual de forma que possa ser utilizado de forma semelhante à iteração em um array.

O foco principal é em separar a responsabilidade de gerenciar o armazenamento dos dados da coleção, da forma como eles são percorridos.
  •   Um iterador simples poderia percorrer a lista em ordem sequencial.
  •   Um outro iterador poderia filtrar alguns dados para serem percorridos.
  •   Um outro ainda, poderia percorrer a sequência segundo algum critério de ordenação.

ESTRUTURA BASICA:



Então, respondendo ao exemplo anterior, ao utilizar o padrão iterator nós podemos acessar os elementos de um conjunto de dados sem conhecer como se deu sua implementação, não há a necessidade de se preocupar se ele foi estruturado com Arraylist ou Matriz.

O método da criação do iterator retorna um iterador de Lista que tem o ArrayList produtos como conjunto. Para a classe que utiliza matriz para armazenar os produtos esse método cria um Iterator que retorna um iterador de Matriz

Pronto, agora os diferentes conjuntos estão encapsulados numa interface comum. Agora falta implementar os iteradores.

A lista será mostrada pela Interface comum aos produtos criada para o Iterator.

A Interface do Iterador define um TIPO para acessar os elementos de uma coleção qualquer.
Ele está implementado com os métodos genéricos para percorre uma coleção:

  • boolean hasNext() : Determina se há um próximo elemento apontado pelo iterador
  • Object next(): Recupera o próximo elemento apontado pelo iterador  
  • void remove(): Remove o elemento recuperado pelo iterador

Como criar um Iterador?

Simples, importar ele e definir a coleção a ser iterada:
import java.util.ArrayList;
import java.util.Iterator;


Exemplo de Iteração:
import java.util.ArrayList;
import java.util.Iterator;
public class produtos {
 public static void main(String args[]) {
  ArrayList<String> produtos = new ArrayList<String>();
   //Adicionando elementos no array
   produtos.add("Coca-Cola");
   produtos.add("Pepsi");
   produtos.add("Sprite");
   produtos.add("Guarana");
   produtos.add("Sukita");
   produtos.add("Kuat");
   produtos.add("Fruki");
  
  //Criacao do Iterador
  Iterator<String> it = produtos.iterator();
  System.out.println("Tamanho da Lista antes da Iteração " + produtos.size());

  //Usando o Iterator pra checar se tem produtos
  while (it.hasNext()) {
   //Obtemos o proximo elemento
   String s = it.next();
   System.out.println(s);
   //Se nao for Coca-Cola, remove
   if (!s.equals("Coca-Cola")) {
    it.remove();
   }
  }
  System.out.println("\nTamanho da Lista depois da Iteração " +
  produtos.size());
  for(String s: produtos){
   System.out.println(s);
  }
 }
}


SAIDA DESSE EXEMPLO:
Tamanho da Lista antes da Iteração: 7
Coca-Cola
Pepsi
Sprite
Guarana
Sukita
Kuat
Fruki


Tamanho da Lista depois da Iteração: 1
Coca-Cola


Pode se ver neste exemplo uma característica interessante do Iterator, remover ao mesmo tempo que ocorre a iteração.

Vemos então que o Iterator tem uma grande aplicabilidade, como;
  •  Acessar conteúdo de uma coleção sem expor sua representação interna
  •  Suportar múltiplas plataformas de iteração
  •  Prover uma interface única para varrer coleções diferentes, isto é chamado de iteração polimórfica.
Referências:
Use a Cabeça! Padrões de Projeto de Eric & Elisabeth Freeman.
Google Books - Use a Cabeça ! Padrões de Projetos (design Patterns)

Padrão de Projeto Iterator em Java - Conceitos, Funcionamento e Aplicação prática, Devmedia:
http://www.devmedia.com.br/padrao-de-projeto-iterator-em-java-conceitos-funcionamento-e-aplicacao-pratica/28748

Sérgio Taborda’s Weblog por Sérgio Taborda, Iterator:
http://sergiotaborda.wordpress.com/desenvolvimento-de-software/java/patterns/iterator/



Marcos Vinicius Scholl:
Graduando em Tecnologia em Análise e Desenvolvimento de Sistemas - TADS 
Universidade Federal do Rio Grande - FURG 
Instituto Federal de Educação, Ciência e Tecnologia do Rio Grande do Sul IFRS - Campus Rio Grande 
Rua Eng. Alfredo Huch, 475 - Rio Grande, RS - Brasil - 96201-460

Sobre o autor:
Marcos Vinicius Scholl está na internet desde o longínquo ano de 2002. Estuda na área de Tecnologia de Informação. É entusiasta na área de tecnologia. Gremista de paixão e anticolorado por prazer!

Métodos Nativos

Native Methods

Utilizando Métodos Nativos (Native Methods) em Java.

Métodos nos quais já foram implementados em C ou C++ e utilizados em aplicativos da mesma linguagem podem ser reutilizados nos aplicativos Java através de Métodos Nativos.

Usando a palavra chave "native" em um método de uma classe ela altera o compilado no qual o método será definido externamente, os métodos nativos como não tendo a implementação suas declarações são similares a métodos abstratos.

Ex:
class  OlaMundo{
    public native void ola();
}


Primeiramente essa classe deve ser compilado normalmente “javac OlaMundo.java” após deve ser utilizado a classe utilitária "javah" para criar um arquivo de leitura C da classe OlaMundo "javah OlaMundo" que pode ser achada no diretório jdk/bin.

Ex:
#include <jni.h="">
#ifndef  _Included_OlaMundo
#define _Included_OlaMundo

Extern “C” {

    /*
    *Class: OlaMundo
    *Method: ola
    *Sognature: ()V
    */

    JNIEXPORT void JNICALL Java_OlaMundo_ola (JNIRev *, jclass);

    #ifdef __cplusplus 
}

#endif
#endif


Dentro do arquivo esta a declaração da função Java_OlaMundo_ola, o JNIEXPORT e JNICALL são necessários para a utilização da biblioteca dinâmica.

A seguir a classe C deve ser implementada dessa forma, copiando a leitura do arquivo.

Ex:
#include "OlaMundo.h"
#include <stdio.h="">

JNIEXPORT void JNICALL Java_OlaMundo_ola (JNIRev * env, jclass cl);
{
    Print("Ola Mundo em JAVA utilizando o print de C!/n");
}


Deve-se carregar o biblioteca dinâmica porem a linha de comando muda dependendo do SO.

Ex:

Linux compilador Gnu:
-gcc -fPIC -I jdk/include/linux -shered -o libOlaMundo.so OlaMundo.c

Windows compilador Microsoft:
cl -I jdk\include -I jdk\include\win32 –LD OlaMundo.c –FeOlaMundo.dll


Por último deve ser chamado um método System.loadLibrary() para assegurar que a biblioteca será carregada antes do primeiro uso da classe.

Ex:
class TesteOlaMundo{
    public static void main (String[] args){
     OlaMundo.ola();
    }

    Static{
        System.loadLabrary("OlaMundo");
    }
} 


Referencia: Livro Core Java Volume II – Advanced Features do autor Gary Cornell

Introdução a Refatoração



Segundo o autor refatoração é o processo de alteração de um sistema de software de modo que o comportamento externo do código não mude, mas que sua estrutura interna seja melhorada.
 
Para que seja mais fácil entender vou utilizar o exemplo usado pelo autor. Um programa para calcular e imprimir o valor devido por um cliente em uma vídeo locadora. O programa calcula o valor devido, que depende de quanto tempo o filme foi alugado e identifica o tipo do filme. Há três tipos de filmes: normais, infantis e lançamentos.

Classes




Conforme o exemplo do autor os usuários do sistema gostariam que a conta fosse impressa em HTML, para que esta possa ser acessada pela WEB. Considerando o código atual teríamos que implementar um novo método para a conta em HTML, que duplicaria muito do comportamento do método conta existente, pois é impossível reutilizar o código do mesmo.

Para poupar trabalho poder ia-se copiar o código do método conta, e fazer alterações para adapta-lo ao método contaHml, porém está prática pode gerar uma inconsistência uma vez que as regras de cobrança podem mudar, assim o desenvolvedor teria que aplicar essas mudanças nos dois métodos.

O primeiro passo da refatorção é criar um sólido conjunto de testes, e executa-los antes de começar a alterar o código, para que se obtenham os resultados antes da alteração. A cada alteração concluída devem-se executar os mesmo testes para verificar se as funcionalidades permanecem iguais. 

Depois de criado os casos de testes, devemos decompor o método conta em partes menores, visto que este método é muito extenso e não pode ser reaproveitado. O autor faz muitas alterações na estrutura do código, mas vamos focar apenas no switch que obtém o valor de cada filme, então criamos um método que tenha esta funcionalidade, assim quando for criado o método contaHtml podemos utiliza-lo ao invés de copia-lo.



Após a alteração feita é importante testar para verificar se as funcionalidades permanecem integras, uma alteração importante neste método seria alterar o nome da variável cada para um nome mais intuitivo, então o autor chamou-a de umaLocação.





Como na maior parte dos casos, um método deve estar no objeto cujos dados ele usa. Assim, o método deve ser movido para a classe Locação.



Feito isso podemos utilizar este método tanto para gerar o valor de cada locação do método conta quanto do método contaHtml. Caso haja alguma alteração no cálculo do valor de cada locação, como por exemplo, inserir uma nova categoria de filme devemos então alterar apenas este método.


Referências

Refatoração:Aperfeiçoando o Projeto de Código Existente do Martin Fowler, Arquiteto de Software.

Padrões de Projeto

Bom, meu post vai ser sobre o livro Padrões de Projeto, dando uma breve explicação do que tem no livro: O livro Padrões de Projeto reúne um total de 23 padrões, que baseado em problemas nos fornece soluções que podemos utilizar em um projeto de software. O livro separa os padrões em 3 critérios: criação, estrutural e comportamental. Cada critério tem seus padrões relacionados. Os padrões também se aplicam quanto as classes e quanto aos objetos. Logo abaixo uma tabela que tem logo no inicio do livro:
 Criação            Estrutural     Comportamental
Classe Factory Method    Adapter(class)   Interpreter/template method

Objeto Abstract Factory   Adapter(object)  Chain of Responsibylity
 Builder            Bridge     Command
 Prototype    Composite     Iterator
 Singleton    Decorator     Mediator
             Façade     Memento
             Flyweight     Observer
             Proxy     State
                       Strategy
                       Visitor




Bom, passado a tabela da pra ter uma melhor ideia da divisão dos padrões e de suas aplicações. Como não tenho tempo de ler o livro todo, fui lendo sobre os padrões, achei interessante o Singleton,ele esta na pagina 130 do livro Padrões de Projeto.

Singleton é um Padrão de Projeto que nos garante que tenha somente uma instância de uma determinada classe, tendo um ponto de acesso global ao objeto na classe.O livro aborda como um exemplo de motivação uma impressora no sistema, onde temos muitas impressoras, mas teríamos que ter somente um spooler de impressão. Para obtermos somente uma instância da classe pode ser criado um método estático que chama o construtor da classe e verifica se não tem instância, caso não tenha retorna uma nova, caso tenha retorna a mesma. Um exemplo que achei em java:

public class MySingleton{
 
   //variável estativa que ira contes a instancia do método
   private static MySingleton instance;
 
   //contrutor do método
   private MySingleton(){
   }

   //metodo public estatico de acesso unico ao objeto
   public static MySingleton getInstance(){
 if(instance==Null){
    return new MySingleton
         }
   return instance;

  }
}

Visto no exemplo acima, não teríamos como criar uma instância da classe sendo o construtor privado, porem o método publico da classe é estático e esse pode ser invocado sem a necessidade de uma instância, assim resolvendo nosso problema,que ao chamar o método estático automaticamente se cria uma instância da classe, ou então devolve a mesma que já exista.

Outro padrão que achei interessante é o padrão Adapter, esse padrão tem como objetivo adaptar a interface de uma classe para que seja utilizado por outra classe, um exemplo seria um toolkit, onde temos uma classe que precisa ser utilizada em nossos sistemas, porem para fazer o encaixe da classe precisamos de um adaptador, para que possamos utilizar a biblioteca, uma das vantegens de usar esse padrão é vincular o cliente a uma interface separado e não diretamente na classe que vai ter suar interface adaptada, um exemplo de código em Java:

public class TomadaDeDoisPinos{
  public  void ligarNaTomadaDeDoisPinos(){
       System.out.println(“ligado na tomada de dois pinos”);
        }
}

public class TomadaDeTresPinos{
  public  void ligarNaTomadaDeTresPinos(){
      System.out.println(“ligado na tomada de tres pinos”);
        }
}

public class AdapterTomada  extends TomadaDeDoisPinos {
  private TomadaDeTresPinos  tomadaDeTresPinos;
   
 public AdapterTomada(TomadaDeTresPinos tomadaDeTresPinos){
  this.TomadaDeTresPinos = tomadaDeTresPinos;
        }

public  void LigarNaTomadaDeDoisPinos(){
        tomadaDeTresPinos. LigarNaTomadaDeDoisPinos;
        }


}


No exemplo de código acima temos uma classe AdapterTomada, quer ser ve como adaptador para interface das outras duas classes.Segue o exemplo do código em funcionamento:

public class Teste{
 public static void main(String argumentos[]){
  TomadaDeTresPinos  tomadaTresPinos = new  TomadaDeTresPinos;
  
  AdapterTomada adaptador  = new AdapterTomada(tomadaTresPinos);
  
  adaptador. LigarNaTomadaDeDoisPinos();
    }
}

Referências :
http://www.devmedia.com.br/padrao-de-projeto-adapter-em-java/26467
http://pt.wikipedia.org/wiki/Singleton
Livro Padrões de Projeto – Soluções Reutilizáveis de Software Orientado a Objetos

Bom , acho que vou concluir meu post por aqui, porque tem muitos padrões, tenho que ler com calma : ).

Autor:
Andrei Espelocim Garcia
Graduando em Tecnologia em Análise e Desenvolvimento de Sistemas- IFRS- CAMPUS Rio Grande

Introdução a Modelagem de Domínios

Neste post irei abordar uma introdução à modelagem de domínios, com algumas boas dicas e práticas, através de exemplos elaborados de forma simples em que o leitor entenda e compreenda a ideia proposta.

Todos os softwares ao serem projetados são relacionados a alguma atividade ou interesse do usuário. Este interesse em que o usuário aplica o programa é o Domínio do software.

Um domínio geralmente está ligado ao mundo físico, por exemplo, um programa de reservas de ingressos de jogos de futebol, envolve pessoas reais entrando em estádios de futebol reais. Alguns softwares são intangíveis, o domínio de um software bancário, por exemplo, envolve o dinheiro, finanças. Porém, existem exceções, como um software IDE(Integrated Development Environment), ou Ambiente integrado de desenvolvimento, que gerencia o próprio desenvolvimento de softwares.

Para criar softwares que desempenham as atividades de forma coerente para os usuários, a equipe de desenvolvimento ou o desenvolver, devem trazer consigo muitos conhecimentos sobre o domínio do projeto. A quantidade de conhecimentos sobre o assunto pode muitas vezes ser absurda, para isso existem os Modelos, que são uma forma de organizar e selecionar os conhecimentos de um domínio, com coerência para criar uma boa estrutura.

Um modelo não se trata de um diagrama específico, é apenas uma espécie de rascunho “sofisticado” de como virá a ser o diagrama final.

Observe, abaixo, uma modelagem de domínio de um software de caixa eletrônico bancário. O domínio, neste exemplo, se trata de clientes movimentando seu dinheiro. Realizando, assim, operações e movimentações de suas contas através do software.
O primeiro modelo elaborado com todas as informações poderia ser algo deste tipo:


Após um refinamento das informações e aplicação dos princípios de modelo, poderíamos melhorar o exemplo anterior e chegar a um novo, algo assim:


Este post apenas introduz a ideia de modelagem de domínios, este exemplo poderia ser mais refatorado, mas deixo o interesse de ir além aos leitores.

Para se aprofundar mais sobre este assunto, recomendo a leitura do livro referênciado.

Referências:
- EVANS, E. Domain-Driven Design: Tackling Complexity in the Heart of Software. New York: Addison-Wesley, 2004.
- BRIÃO, W, E. Trabalho de Programação Orientada a Objetos. Rio Grande: IFRS, 1°Sem/2013. Acesse neste link.

Enumerados

Antes de o tipo enum ser adicionado em Java, eram usados inteiros nomeados para fazer seu trabalho.
Ex:

public static final int MES_JANEIRO = 1;
public static final int MES_FEVEREIRO = 2;
public static final int MES_MARCO = 3;
//...

Porem usando esse desse tipo, ele tem muita deficiência (tipo multiplicar um pelo outro, igualar, e etc...) e também não existe uma maneira fácil de converter constantes enumeradas int em strings. Programas que usam esse tipo de padrão são muito frágeis.
A partir do Java 1.5 já esta incluso o tipo enum Java. Sua principal funcionalidade é agrupar valores de mesmo sentido e também deixar o código mais legível. No exemplo a seguir agrupamos os nomes dos meses dentro de um enum chamado Mês.

public  enum Mes {JANEIRO, FEVEREIRO, MARCO} //...

Assim se você declarar um parâmetro do tipo Mes do qual o objeto passado só poderá receber valores que estão em nosso enum.

Mes m = Mes.JANEIRO

// A VARIAVEL M RECEBERA JANEIRO

m = Mes.FEVEREIRO

// AGORA M RECEBEBERA FEVEREIRO

m = Mes.ALGUMACOISA

// RESULTA EM ERRO PORQUE "ALGUMACOISA" NÂO
//  É UM VALOR DO TIPO ENUMERADO MES

Tipos enum's são implicitamente final e suas constantes são static. São usadas com mais freqüência quando se precisar de um conjunto finito de constantes. No enum você também pode adicionar método e campos arbitrários, NUNCA são usados dentro de métodos.
O enumerado é muito semelhante a de uma classe, porém todos seus valores nunca poderão ser modificados. O construtor por exemplo é muito semelhante a de classe, só que sua usabilidade se da somente para indicar o que cada valor contido na constante significa.
Não é aconselhado usar o método “ordinal()” para retornar o valor da posição da constante. É muito melhor armazená-lo em um campo de instancia, pois caso algum dia você alterar seu código e mudar a seqüência das constantes não mudaria os valores delas, como aconteceria se usássemos o método ordinal.

public  enum Mes {
 JANEIRO(1),
 FEVEREIRO(2),
 MARCO(3);

 private final int numeromes;

 private Mes(int numeromes){
  this.numeromes=numeromes;
 }
}

Exemplo de uso de gets, construtor e toString(Override) :

public class Teste {
    public  enum Mes {
        JANEIRO("Janeiro",31),
        FEVEREIRO("Fevereiro",28),
        MARCO("Março",31);
        //...
        private final int dias;
        private final String nome;
        
        private Mes(String nome, int dias){
            this.nome = nome;
            this.dias = dias;
        }
        public int getDias(){
            return dias;
        }
        public String getNome(){
            return nome;
        }
        @Override
        public String toString(){
            return "Mes: "+nome+" tem "+dias+" dias.";
        }

    }
    
    public static void main(String[] args) {
       
        //PERCORRER VALORES
        for(Mes m  : Mes.values()) {
                System.out.println(m); // Automaticamente
                                       // chama m.toString()
        } 
    }
}

Referências:

Java Efetivo do Joshua Block, Arquiteto de Software na Google.

Blog Red Pill do Marcio Torres, Analista e Desenvolvedor de Sistemas/Professor no IFRS

Site Tiexpert, post do Denys William Xavier.

Tipos Genéricos (Generic Types)

Vamos imaginar que precisamos criar uma classe chamada Celular, mas nós não sabemos qual tipo de celular que iremos ter por que afinal existem vários. Ele pode ser de um chip, dois, três ou quatro chips, ser touch ou não e por aí vai. Então vamos criar as classes.

public class CelularUmChip {

    private String marca;
    private int numeroChip1;
   
    public CelularUmChip(String marca, int numeroChip1, 
            boolean ehTouch) {
        this.marca = marca;
        this.numeroChip1 = numeroChip1;
        this.ehTouch = ehTouch;
      
    }    
}

class CelularDoisChips {

    private String marca;
    private int numeroChip1, numeroChip2;    

    public CelularDoisChips(String marca,int numeroChip1, 
            int numeroChip2) {
        this.marca = marca;
        this.numeroChip1 = numeroChip1;
        this.numeroChip2 = numeroChip2;
    }
}

Deu de ver que o código vai ficar repetido né? É aí que utilizamos os Generics. Porém os Generics só vieram há ser implementados na versão 1.5 do Java, até então era necessário pegar os tipos como Object e fazer casting para qual o tipo desejado.
A classe Celular ficaria assim:
public class Celular{
 private Object cellphone;

 public Celular(Object cellphone){
  this.cellphone = cellphone;
 }
 
 public Object getCellphone(){
  return cellphone;
 }
}

E no Main seria necessário fazer o casting como representado no código abaixo.

public class Main{
 public static void main(String[] args){
  Celular c = new Celular(new CelularUmChip("Motorola", 81909090));
  
  CelularUmChip c1 = (CelularUmChip)c.getCellphone();
 }
}

Programando desta maneira seria muito fácil ocorrer erros de Casting, como o clássico "ClassCastException", que dispara quando estamos instanciando a classe errada.

Mas a partir do Java 1.5 já se pode usar os Generics. O que ele faz é instanciar uma classe para que ela receba qualquer tipo de classe ou qualquer tipo primitivo, como int, double e etc. Para instanciar uma classe Generics basta colocar ao lado do nome um <T>, assim já estamos dizendo ao compilador que ele irá receber tal classe quando estiver em compilação. O que vai entre <> não se limita somente ao “T”, há outros placeholders:


E – Element

K – Key

N – Number

T – Type

V – Value

Os Generics permitem o uso de mais de um placeholder no mesmo <>, como por exemplo:
Example <T, N, V>
Vamos refazer nosso código agora utilizando Generics.

public class Celular<T>{

    private T cellphone;

    public Celular(T cellphone) {
        this.cellphone = cellphone;
    }    

    public T getCellphone() {
        return cellphone;
    }    
}
Agora nossa classe Celular vai poder receber qualquer uma das outras que foram declaradas antes.
public class Main {
    public static void main(String[] args) {
        
      Celular<CelularUmChip> c = new Celular(new CelularUmChip("Motorola", 
              81909090));
      
        Celular<CelularDoisChips> c2 = new Celular(new CelularDoisChips("Nokia",
                90909090, 99999090));
    }
}

Referência:

Java Efetivo do Joshua Block, Arquiteto de Software na Google
Site Tiexpert, post do Denys William Xavier
Site Plugmaster, post do Dayvid Lima.

Tratamento de erros em java


Tratamento de erros pode parecer tão simples mas são muitos fatores a se considerar, a entrada pode estar errada o dispositivo pode falhar, é responsabilidade do programador certificar-se que o código não trave com esses erros. O tratamento de erro domina completamente muitos códigos fonte, ou seja, se torna praticamente impossível ver oque o código faz devido a tantos tratamentos espalhados pelo código. O tratamento é um recurso importante, mas se ele obscurecer a logica, está errado.

Uma coisa interessante sobre exceções com try-catch-finally é que elas definem um escopo dentro de seu programa, que ao executar a parte do try você declara que aquela execução pode ser cancelada a qualquer momento, e então, continuar no catch. Vejamos um exemplo. Precisamos criar um código que acesse um arquivo e consulte alguns objetos em série. Começamos com um teste de unidade que mostra como capturar uma exceção se o arquivo não existir.

@Test (expected = StorageException.class)
public void retrieveSectionShouldThrowOnInvalidFileName() {
	sectionStore.retrieveSection(“invalid – file”);
}

O teste nos leva a criar esse stub:

public List<recordedgrip> retrieveSection(String sectionName) {
	// retorno fictício até que tenhamos uma implementação real
	return new ArrayList<recordedgrip>();
  Nosso teste falha porque ele não lança uma exceção. Em seguida, mudamos nossa implementação de modo a tentar acessar um arquivo inválido. Essa operação lança uma exceção:

public List<recordedgrip> retrieveSection(String sectionName) {
	try {
		FileInputStream stream = new FileInputStream(sectionName)
	} catch (Exception e) {
	  throw new StorageException(“retrieval error”, e);
	}
	return new ArrayList<recordedgrip>();
}
Nosso teste funciona agora porque capturamos uma exceção. Neste momento podemos refatorar. Podemos reduzir o tipo de execução que capturamos para combinar com aquele que realmente é lançado pelo construtor FileInputStream: FileNotFoundException:

public List<recordedgrip> retrieveSection(String sectionName) {
	try {
		FileInputStream stream = new FileInputStream(sectionName);
		stream.close();
	} catch (FileNotFoundException e) {
	  throw new StorageException(“retrieval error”, e);
	}
	return new ArrayList<recordedgrip>();
}
 Agora que definimos o escopo try-catch, podemos construir o resto da lógica que precisamos, que será adicionada na criação do FileInputStream do close e poderá fingir que nada de errado aconteceu.

Não se esqueça de criar mensagens de erro informando a operação e tipo de falha que ocorreu, pois cada exceção lançada deve fornecer contexto suficiente para determinar a fonte e a localização de um erro.

Existem muitas formas de classificarmos erros seja pela origem: de onde vieram, ou pelo tipo: são falhas do dispositivo ou da rede ou de erros de programação. Geralmente, uma única classe de exceção esta bom para uma parte especifica do código. Use classes diferentes apenas se houver casos em que você queira capturar uma exceção e permitir que outra passe.

Se você retornar um null basicamente esta jogando o problema em cima dos seus chamadores, basta esquecer uma verificação de null para que o programa se perca. Pior do que retornar null é passar null como parâmetro. A menos que esteja trabalhando com uma API que esteja esperando por null.

Por: Bruno Lima.


BIBLIOGRAFIA [Martin]: Agile Software Development: Principles, Patterns, and Practices, Robert C. Martin, Prentice Hall, 2002.