quarta-feira, 9 de dezembro de 2009

Repositorio, e especificações como implementar - Parte 2

quarta-feira, 9 de dezembro de 2009
Em meu post anterior citei como fazer a implementação flexível do padrão Repositório e Especificação, citado por Eric Evans juntamente com o Hibernate, realmente as pessoas tem muita confusão de como implementar, uma coisa sempre e certa a sempre 1001 maneiras de implementar algo, e como Eric Evans, em seus exemplos, foi dado do SQL direto a implementação da Especificação e do Repositório, mas nós podemos usar o Hibernate que facilita muito a vida, e ele disse também sobre isto, que muitas vezes o sistema de mapeamento objeto relacional pode nos ajudar.

Mas vamos ao que interessa, no post anterior falei a respeito de como implementar a Especificação e vimos que a mesma serve para manter as regras de negócio da aplicação toda sobre um único lugar, assim o sistema se torna de mais fácil manutenção, e podemos ganhar muito com isto, nem sempre e fácil fazer a implementação destes padrões, visto a grande confusão e insistência em fazer as coisas usando as receitas de bolo da programação.

Algo que com certeza podemos mais cedo ou mais tarde fazer nos nossos sistemas é a junção de filtros para obter um resultado, vimos que a Especificação pode nos ajudar a abstrair do cliente toda a complexidade do filtro da consulta e manter as coisas simples, mas vamos a um exemplo real no sistema.

Digamos que o cliente diga o seguinte a você que está desenvolvendo o sistema.

"O relatório de clientes está bom mas, gostaríamos que na tela que faz a configuração do relatório seja incluído outros filtros onde gostaríamos de filtrar os clientes do relatório que possuem não contatamos a mais de 20 dias, visto que estes clientes devem ter uma atenção especial, assim como já funciona na tela do cadastro, e gostaria além disso também que fosse exibido os que tiveram uma reclamação do nosso serviço no histórico."

Repare que neste dialogo o cliente solicitou que você casa-se ou junta-se filtros diferentes, um filtro já existe, sendo que já está funcionando na tela de cadastro, a Especificação que já está implementada e a de clientes sem contato a mais de 20 dias, agora ele te Especificou algo novo, o cliente que possui uma ou mais reclamações. Vejamos então o que temos e o que deveríamos desenvolver:

public class EspecificacaoClientesComReclamacao implements Especificacao {

    private Integer numReclamacoes;
 
    public EspecificacaoClienteComReclamacao(Integer numReclamacoes){
        this.numReclamacoes = numReclamacoes;
    }
 
    public Criterion configurarCriteria(Criteria criteria,Class alvo){
        if (alvo != Cliente.class) return null;
        return Restrictions.gt("numReclamacoes", numReclamacoes );
    }
}
E a outra especificacao:

public class EspecificacaoClientesSemContato implements Especificacao {
    private Integer dias;
 
    public EspecificacaoClienteSemContato(Integer dias){
        this.dias = dias;
    }
 
    public Criterion configurarCriteria(Criteria criteria,Class alvo){
        if (alvo != Cliente.class) return null;
        Date dataAtual = new Date();  
        Calendar calendarData = Calendar.getInstance();  
        calendarData.setTime(dataAtual);  
        calendarData.add(Calendar.DATE,dias);  
        Date dataInicial = calendarData.getTime();  
  
        return Restrictions.gt("ultimoContato", dataInicial );
    }
}

Repare que no dialogo o cliente queria executar estas duas especificações para obter a lista?

Como fazer isto então? Bem conforme Evans comentou podemos pegar emprestado o conceito de operadores lógicos, o que são estes operadores lógicos? Seria o seguinte:

AND, OR, NOT

Veja como ficaria para usarmos os operadores lógicos, e assim agrupar as duas Especificações:
Especificacao clientesSemContato = new EspecificacaoClientesSemContato();

Especificacao clientesComReclamacao = new EspecificacaoClientesComReclamacao();

Especificacao especificacoes = clientesSemContato.and(clientesComRelamacao);
Repare que na ultima linha juntamos as duas especificações e agora poderíamos passar para o repositório as especificações agrupadas assim.
RepositorioCliente clientes = new RepositorioCliente();
clientes.recuperarPorEspecificacao(especificacoes);
Desta forma estaríamos passando não uma mas sim duas especificações que poderiam ser executadas.

E digamos que queríamos os clientes sem contato OU os clientes com reclamação? Poderíamos fazer assim:
Especificacao especificacoes = clientesSemContato.or(clientesComRelamacao);
Repare agora o uso do operador or? O mesmo se aplica ao NOT onde queremos os clientes sem contato que não tiveram reclamação:
Especificacao especificações = clientesSemContato.not(clientesComRelamacao);

Repararam no poder deste simples sistema? O cliente tem total liberdade para especificar que resultado deseja sem se preocupar em como ele será obtido, sendo que como ele é obtido fica a cargo do repositório.


Pois bem como implementar isto em Java e usando o hibernate?

A Especificação que era uma interface agora irá usar o padrão Template Method, ela passará a ser conforme mostrado abaixo:

public abstract class Especificacao {
    public Especificacao and(Especificacao... especificacoes) {
        List<especificacao> especs = new ArrayList<especificacao>();
        for (Especificacao e : especificacoes)
            especs.add(e);
        especs.add(this);

        return new EspecificacaoAnd(especs.toArray(new Especificacao[especs.size()]));
    }

    public Especificacao not() {
        return new EspecificacaoNot(this);
    }

    public Especificacao or(Especificacao... especificacoes) {
        List<especificacao> especs = new ArrayList<especificacao>();
        for (Especificacao e : especificacoes)
            especs.add(e);
        especs.add(this);

        return new EspecificacaoOr(especs.toArray(new Especificacao[especs.size()]));
    }

    @SuppressWarnings("unchecked")
    public abstract Criterion configurarRestricao(Criteria criteria, Class classe) throws DomainException;

    public abstract boolean satisfazEspecificacao(Object o) throws DomainException;
    }
}
E os objetos que fazem uso do operador AND,OR,NOT são implementados no exemplo abaixo:

Especificação Or:

class EspecificacaoOr extends Especificacao {

    private Especificacao[] especificacoes;

    public EspecificacaoOr(Especificacao... especificacoes) {
        this.especificacoes = especificacoes;
    }

    @SuppressWarnings("unchecked")
    public Criterion configurarRestricao(Criteria criteria, Class classe) throws DomainException {
        Disjunction or = Restrictions.disjunction();

        for (Especificacao espec : especificacoes) {
            if (espec == null) continue;
            Criterion ret = espec.configurarRestricao(criteria, classe);
            if (ret != null)
                or.add(ret);
        }

        return or;
    }

    public boolean satisfazEspecificacao(Object o) throws DomainException {
        for (Especificacao espec : especificacoes) {
            boolean retorno = espec.satisfazEspecificacao(o);
            if (retorno)
                return true;
        }
        return false;
    }
}
Especificação AND:

class EspecificacaoAnd extends Especificacao  {
    private Especificacao[] especificacoes;
    public EspecificacaoAnd(Especificacao... especificacoes) {
    this.especificacoes = especificacoes;
    }
    @SuppressWarnings("unchecked")
    @Override
    public Criterion configurarRestricao(Criteria criteria,Class classe) throws DomainException {
        Conjunction and = Restrictions.conjunction();
        List<criterion> retorno = new ArrayList<criterion>();
        for (Especificacao espec : especificacoes) {
            if (espec == null) continue;
            Criterion ret = espec.configurarRestricao(criteria,classe);
            if (ret != null){
                retorno.add(ret);
                and.add(ret);
            }
        }

        if (retorno.size() == 0) return null;
  
        return and;
    }

    @Override
    public boolean satisfazEspecificacao(Object o) throws DomainException{
        for (Especificacao espec : especificacoes) {
            Boolean retorno = espec.satisfazEspecificacao(o);
            if (!retorno)
                return false;
        }
        return true;
    }
}
Especificação NOT:

class EspecificacaoNot extends Especificacao {

    private Especificacao espec;

    public EspecificacaoNot(Especificacao especificacao) {
        this.espec = especificacao;
    }

    @SuppressWarnings("unchecked")
    public Criterion configurarRestricao(Criteria criteria,Class classe) throws DomainException {
        if (espec == null) return null;
        Criterion ret = espec.configurarRestricao(criteria,classe);
        if (ret != null)
            return Restrictions.not(ret);

        return null;
    }

    public boolean satisfazEspecificacao(Object o) throws DomainException {
        return !espec.satisfazEspecificacao(o);
    }
}
Com estas especificações agora podemos usar o sistema conforme exemplificado e passar para o repositório agora não mais uma especificação e sim varias.

Conforme podemos ver alisto abaixo o real benefício desta implementação:

1. Classes mais leves: O repositório passa a ter uma interface simples e não recheada de métodos.
2. As regras da aplicação ficam em apenas um lugar.
3. As especificações podem ser combinadas e assim filtros mais complexos, com uso dos operadores lógicos.
4. Maior clareza, e encapsulamento da regra.

Em outro Post mostrarei como utilizar as especificações para executar outras coisas como recuperar um conjunto de registros paginado, Ordenado, usando especificações e como fazer isto na prática, postarei um código de exemplo.


Nenhum comentário :

terça-feira, 1 de dezembro de 2009

Repositorio, e especificações como implementar

terça-feira, 1 de dezembro de 2009
Algo que inconfundivelmente geralmente toda aplicação precisa ter, é o acesso a dados em um banco de dados. Antigamente as aplicações acessavam os dados gerando consultas diretamente da interface do usuário, esta abordagem acoplava a consulta com a interface visual, o que inevitavelmente levava a duplicar consultas em mais de uma área, como para tirar um relatório e para uma consulta ao sistema.

Mas ai as coisas foram evoluindo, a melhor coisa seria então separar a camada que acessava os dados da camada visual ou qualquer outra camada, para isto foi introduzido um conjunto de classes que faziam a separação dos dados sendo que estas classes agora eram responsáveis por fazer de fato o acesso aos dados, converter em objetos e repassar para o seu cliente (quem invocou o método) uma lista de objetos que representavam assim uma consulta ao banco de dados.

Quando uma solução se repete demais, podemos dizer que ela é um padrão, portanto assim surgiu o DAO ou Pattern DAO.

Este padrão visava além de desacoplar do cliente que necessita de dados do banco, tinha também o propósito de permitir o suporte a diversos bancos de dados, podendo a fonte dos dados vir até mesmo de um arquivo de texto, um WebService, XML, ou outra fonte qualquer, mas isto trouxe uma complexidade que ainda precisava ser atacada, a questão dos bancos de dados, diversos bancos de dados também era um problema visto que geralmente aquele o aquele outro banco tinha as suas peculiaridades, embora o uso do pattern DAO tenha desacoplado e permitido diversas implementações de acesso a fontes de dados diferentes, ainda era custoso ter que desenhar para bancos diferentes, além de ser extremamente repetitivo a aplicação do padrão, para permitir o acesso a uma fonte diferente de dados.

Como forma de unificar isto surgiu em cena um framework muito conhecido, o Hibernate, que agora fazia com que o acesso aos dados fosse facilitado, os DAOs agora podiam ser feitos de uma forma mais fácil.

Ainda em outro campo o Hibernate influenciou fortemente a criação da especificação JPA, que veio para substituir as Entity Beans CMP da especificação EJB 2, esta foi mais uma evolução onde agora mapeávamos diretamente através de anotações uma entidade e assim fazer o acesso aos dados.

Ao analisar, hoje vemos que progredimos muito com respeito ao acesso de dados, mas vemos que muitos tem implementado o padrão DAO como uma receita de bolo, muitas vezes sem entender o que ele faz. Muitos acabam implementando ele com a seguinte interface:
public interface DAO<t> {
    int count();
    
    List<t> findAll(int start, int max);

    Lis<t> findAll();

    T findById(Long id);
}
E quando precisão implementar uma consulta mais especifica acabam fazendo assim
public class DAOCliente {
    private List findClientesPorNome(String nome){
    .....
    }
} 
E se agora precisar filtrar por CPF e CNPJ ?

A resposta mais obvia era, implemento mais um método
private List<cliente> findClientesPorCNPJ(String CNPJ){
  .....
}

private List<cliente> findClientesPorCPF(String CPF){
  .....
}
Se pararmos para pensar por um momento veremos que isto faz com que a interface fique inchada, fazendo assim que o sistema fique muito rígido, exemplo de rigidez? Digamos que você precise contar os clientes que começam com um nome, outro método seria então implementado.

Pois bem percebendo isto muitos desenvolvedores, assim como eu vinham buscando soluções para tornar o sistema, mas flexível para consultas.

Ao ler o livro de Eric Evans Domain Driven Design, e ver diversos post do Shoes e muitos outros, pudemos ver uma abordagem melhor para acesso aos dados. Do que uma interface inflada.

Bem vamos explicar a que conclusão chegamos, um dos primeiros pontos que vimos foi que o cliente era responsável por dizer o que queria, isto também ocorria antes, visto que o cliente tinha de dizer que método do DAO era necessário invocar, agora o que fizemos foi diferente, ao invés de implementar rigidamente a consulta sobre o DAO que segundo Shoes, nos passaremos a chamá-lo a partir daqui de Repositório foi encapsular o filtro da consulta sob uma especificação, o que é uma especificação? Nada mais é do que dizer como você quer as coisas, sendo que ela serve tanto para acesso a dados de um banco mais também para validação, vamos a um exemplo para que fique mais claro:

- Primeiro vamos ver um exemplo de uma especificação para validação:

Digamos que você está montando um sistema de estoque e que agora você necessita comprar mais itens dos produtos que estão acabando, geralmente você iria fazer um IF sendo que os produtos que tiverem uma quantidade X seria adicionado:

for ( Produto produto : produtosEstoque) {
    if (produto.getQuantidadeEmEstoque()<15){
        listaDeProdutosAComprar.add(produto);
    }
}
Com certeza este código funciona e você obterá uma lista de produtos que estão com menos de 15 unidades no estoque. Mas um problema é que a lógica de produtos como esta pode ficar dispersa em vários locais da aplicação. Sendo assim você deveria encapsular a lógica de verificação, fazendo uma especificação assim:

Você tem a seguinte interface:

public interface Especificacao {
    boolean satisfaz(Object o);
}

public class EspecificacaoDeProdutosAcabando implements Especificacao {

    private int quantidadeMinima;

    public EspecificacaoDeProdutosAcabando(int quantidadeMinima){
        this.quantidadeMinima = quantidadeMinima;
    }

    public boolean satisfaz(Object o){
 
        // aqui vai a lógica para verificar se o produto não está acabando
 
        if (!(o instanceof Produto)){
            return false;
        }

        return ((Produto) o).getQuantidadeEmEstoque()<quantidadeMinima;
    }
}
Para usar agora você faz assim:

Especificacao produtoAcabando = new EspecificacaoDeProdutosAcabando(15);

for ( Produto produto : produtosEstoque) {
    if (produtoAcabando.satisfaz(produto)){
        listaDeProdutosAComprar.add(produto);
    }
}
Repare que ao fazer assim você encapsulou a lógica de verificação de um produto quanto a se ele deve ser comprado ou não, se agora para modificar a lógica se um produto está acabando, você simplesmente altera em um lugar.

Este sistema tem grande poder para objetos agora também pode ser usado para filtrar registros no banco de dados.

Para fazer isto eu uso para as consultas a api criteria do Hibernate.

A interface da especificação precisa ser modificada agora para o seguinte:

public interface Especificacao {

    boolean satisfaz(Object o);

    Criterion configurarCriteria(Criteria criteria,Object o);

}
O papel do método Criterion configurarCriteria(Criteria criteria,Object o) é criar um criterion do tipo restriction para que possa ser adicionado a criteria e assim efetuar o filtro no sistema.

Veja uma real implementação onde é criado a especificação de login valido para ser usado por um repositório.

Em uma aplicação apenas os usuários com senha e login validos e que estão ativos devem acessar ao sistema. Portanto teremos a seguinte especificação:

public class EspecificacaoLoginValido implements Especificacao {

    private String login;
    private String senha;
    
    public EspecificacaoLoginValido(String login,String senha){
        this.login = login;
        this.senha = senha;
    }
 
    public boolean satisfaz(Object o) {
        if (!(o instanceof Usuario) || o ==null){
            return false;
        }

        Usuario u = (Usuario) o;

        return login.equals(u.getLogin()) 
        && senha.equals(u.getSenha()) 
        && u.isAtivo();

    }    

    public Criterion configurarCriteria(Criteria criteria,Object o){

        if (!(o instanceof Usuario) || o ==null){
            return null;
        }
        
        Conjunction and = Restrictions.conjunction();
        and.add(Restrictions.eq("login",login);
        and.add(Restrictions.eq("senha",senha);
        and.add(Restrictions.eq("ativo",true);
        return and;
    }
}
O seu repositório (DAO) seria assim:

public class RepositorioUsuarios {

    public List recuperarPorEspecificacao(Especificacao espec) {

        Criteria criteria = session.createCriteria(Usuario.class);
        Criteria.add(espec.configurarRestricao(criteria,Usuario.class));
        return criteria.list();
    }
}
Agora você tem um Especificacao que filtra os registros no banco fazendo com que a criteria seja configurada fora do repositório.

Para usar para validação seria assim:

Especificacao loginValido = new EspecificacaoLoginValido("carlos","123");
Usuario usuario = new Usuario();
usuario.setLogin("Carlos");
usuario.setSenha("123");
usuario.setAtivo(true);

loginValido.satisfaz(usuario) // true login, senha e ativo
Para ser executada sobre o repositório seria assim

RepositorioUsuario usuarios = new RepositorioUsuario();
List<usuario> listagem = usuarios.recuperarPorEspecificacao(loginValido);

Isto recupera uma listagem de usuários que safisfazem a especificação.

Este é um exemplo de como usar.

Depois em um outro post explicarei como usar o padrão para casar filtros com o hibernate, seria algo como o exemplo abaixo:

EspecificacaoFaturasVencidas
EspecificacaoClientesInadiplenentes

Como usá-las em conjunto?

Isto fica para outro post.


Nenhum comentário :

segunda-feira, 28 de setembro de 2009

Expressões de ligação - validações customizadas em banco

segunda-feira, 28 de setembro de 2009
Hoje, me deparei com um problema interessante e a sua solução foi realmente muito simples.

Eis o problema os campos de uma determinada tela seriam construídos dinâmicamente, e cada campo tinha as suas peculiaridades de validação, a idéia que tivemos foi então efetuar também a validação de forma dinâmica, veja o exemplo, temos um formulário dinâmico com um campo chamado telefone e o campo telefone é de preenchimento obrigatório se fosse feito em código, você escreveria algo parecido com isto:
"".equals(telefone);
caso o código acima tenha um retorno verdadeiro, o campo não foi preenchido, mas ai vem o problema, não dá para implementar isto de forma dinâmica, onde apenas uma alteração no banco já mudaria as regras de validação, pensei em usar o drools, mas a solução do drools parecia complexa demais para resolver apenas um simples problema de validação. Assim cheguei a solução descrita aqui, basicamente usei algo que todo projeto web tem, o EL (Expressions Language), esta linguagem de expressões foi usada de forma realmente interessante com o uso do SEAM, o SEAM contém uma classe chamada Expressions que cria MethodExpressions e ValueExpressions, no caso o que queria saber é se um VALOR era verdadeiro ou não, portanto usei o ValueExpressions, fiz a seguinte prova conceito.

Em um managedBean coloquei o seguinte código:
Object retorno = Expressions.instance().createValueExpression("#{1<2}").getValue();
System.out.println(retorno);
O interessante deste código foi que ele retornou corretamente o valor true, visto que 1 é menor que 2, portanto percebi que podemos validar assim agora o problema era como validar o formulário, bem foi usado outro objeto do seam chamado Contexts, este objeto permite acesso aos contextos do seam, Contexts.getSessionContext() por exemplo retorna um Context que contém os objeto colocado em sessão, o código ficou assim:
Contexts.getEventContext().set("a", 1);
Contexts.getEventContext().set("b", 2);
Object retorno = Expressions.instance().createValueExpression("#{a<b}").getvalue(); 
Contexts.getEventContext().remove("a");
Contexts.getEventContext().remove("b");
System.out.println(retorno);
Agora ele avaliou o valor de a e b e retornou true, reparem que os valores 1 e 2 não estão mais na expressão, mas sim no contexto de evento, que é o primeiro a ser consultado pelo seam usei ele para evitar conflito de nomes nos outros contextos sendo que logo após a execução o contexto foi limpo, de posse do retorno da expressão podemos agora validar o campo de forma dinâmica, realmente interessante a solução e muito simples de ser usada visto que reutiliza o conhecimento que o programador já possui ao criar as expressões de valor EL.


Nenhum comentário :

quinta-feira, 11 de dezembro de 2008

Padrões de Projeto - Adapter

quinta-feira, 11 de dezembro de 2008
Prezados, no artigo anterior da série, falei sobre o padrão singleton e como o mesmo pode ser usado. Agora veremos sobre outro padrão de projeto chamado Adapter.

Adapter é um padrão que é usando quando se deseja adaptar sua classe para ser usada por outro objeto.

Exemplo:

Sua tomada em casa é de 2 pinos, mas o computador é de 3 pinos então usa-se um adaptador para ligar na tomada (beijamin).

O mesmo em Software:

tenho o seguinte problema:

Preciso comparar uma array de bytes com regex. só que regex somente aceita objetos do tipo CharSequence.
byte[] sca = "helo carlos".getBytes();   

Pattern p = Pattern.compile("^(?i)(helo) .+");   
Matcher m = p.matcher(sca);   
return m.matches();  


O código acima vai da erro, mas eu preciso usar array de bytes. o que fazer?

use um adaptador (Adapter) que adapta a array para ser usada como uma CharSequence,

veja a interface da charSequence:

public interface CharSequence {
int length();
char charAt(int index);
CharSequence subSequence(int start, int end);
public String toString();
}

Aqui está o adaptador:
public class CharSequenceByteArray implements CharSequence {

private byte[] buffer;

public CharSequenceByteArray(byte[] buffer) {
this.buffer = buffer;
}

public int length() {
return buffer.length;
}

public char charAt(int index) {
return (char) buffer[index];
}

public CharSequence subSequence(int start, int end) {
return new CharSequenceByteArray(Arrays.copyOfRange(buffer, start, end));
}
}

agora eu faço assim uso o adaptador:
byte[] sca = "helo carlos".getBytes();

Pattern p = Pattern.compile("^(?i)(helo) .+");
Matcher m = p.matcher(new CharSequenceByteArray(sca));
return m.matches();


Este código não da erro, porque eu adaptei uma interface em outra.

Isto é o padrão adapter.

Att. Carlos


Nenhum comentário :

Gerenciador de Projetos

quinta-feira, 11 de dezembro de 2008
Prezados,

Recentemente em minhas pesquisas pela net encontrei o trac, realmente achei muito bom a ferramenta mas ao pesquisar mais a fundo encontrei o RedMine um trac perfeito...

O Redmine é um gerenciador de projetos de TI, com ele você consegue saber como anda o seu projeto e controlar o desenvolvimento.

Tem ótimo suporte com sistemas de controle de Versão (CVS, SubVersion,GIT) e é multi-projeto.

Acessem a página do Redmine e confiram.

www.redmine.org


Nenhum comentário :

segunda-feira, 8 de dezembro de 2008

Piadas

segunda-feira, 8 de dezembro de 2008
... Arquivo não encontrado, falsifico? (S/N) ...


Nenhum comentário :

Padrões de projeto - Singleton

segunda-feira, 8 de dezembro de 2008
Quando estava iniciando o desenvolvimento orientado a objetos, sempre me perguntava, "para que serve um método estático?", "polimorfismo em que raios de situação usaria isto?", "há interfaces servem apenas para duplicar artefatos.".

E quanto mais passava o tempo mais as minhas pesquisas me mostravam que a orientação a objetos era algo de outro mundo, também para quem desenvolvia em Clipper e via muitas autoridades em programação falarem sobre a morte da orientação a objetos, que a orientação a objetos é ruim, que adiciona complexidade.

Hoje olhando para traz vejo que na verdade o que muitos destes tinham era medo da mudança, e de descobrir, tentar algo novo, o que me ajudou a ver a utilidade da orientação a objetos foi os padrões de projeto.

Quando estava iniciando o meu desenvolvimento em Java, acabei caindo em uma página que falava sobre padrões de projeto J2EE, mais especificamente o DAO. Agora sim me fazia sentido o uso de interfaces e outras coisas. Pude ver a utilidade de uma Factory, Interface, sobrecarga de métodos, etc. Afinal agora a coisa toda estava fazendo sentido.

Você também deve estar curioso, em ENTENDER o que é um padrão de projeto e como utilizá-lo. Pois bem, lá vai.

O que é um padrão de Projeto:

O modelo de programação orientado a objetos é um grande avanço visto que você pode componentizar e melhor organizar o seu sistema. Assim sendo podemos construir programas criando um conjunto de objetos e fazendo os mesmos conversarem entre sí para podermos obter um sistema. Um padrão de projeto é como uma receita de como construir os seus objetos e arranjá-los de forma que você consiga fazer o sistema ser fácil de manter. Vias de passagem manter um sistema não é uma tarefa fácil.

Portanto organizar o sistema de forma que o mesmo mude mais facilmente é muito desejável.

Os padrões de projeto se dividem em 3 partes, sendo que cada parte demonstra um padrão para uma área específica do sistema.
A divisão está entre padrões comportamentais, que mostram formas de os objetos interagirem entre si (comportamento), criacionais, mostrando a forma de criar objetos, e estruturais, no que tange as estruturas de seus objetos.

Nesta série de artigos veremos como os padrões podem nos ajudar, ao invés de apenas apresentar conceitos, veremos em que situações reais eles podem ser usados.

O primeiro padrão a ser apresentado será o Sigleton, este é um dos padrões mais simples de ser usado. E dependendo da situação ele pode ser realmente útil.

Até a próxima.


Nenhum comentário :

sexta-feira, 5 de dezembro de 2008

Maven - você deveria usar...

sexta-feira, 5 de dezembro de 2008
O que é o Maven é uma ferramenta indispensável para o desenvolvimento e gerenciamento de projetos, com certeza você como eu já ficamos de cabelo em pé, porque faltava alguma biblioteca no projeto, ou o sistema da erros estranhos simplesmente por falta de bibliotecas...

O Maven resolve isto de forma interessante, ele usa o conceito de dependência transitiva, assim o funcionamento se da através de um arquivo de configuração chamado POM, e um repositório de bibliotecas identificadas onde ao precisar de uma biblioteca por exemplo basta adicionar a sua identificação no arquivo POM que o Maven baixa a biblioteca no repositório local.

Estas são apenas algumas das funcionalidades do Maven.

Você com certeza todos deveriam usar.


Nenhum comentário :

domingo, 17 de agosto de 2008

Piadas de um computeiro: piada #1

domingo, 17 de agosto de 2008
Mouse não encontrado bater no gato?


Nenhum comentário :

Ordenação por mais de um campo

domingo, 17 de agosto de 2008
Algo comum no desenvolvimento java é a necessidade de ordenar objetos, o java com a API collections dele disponibiliza formas de efetuar esta tarefa, você pode fazer isto:
  1. Implementando a interface Comparable no objeto a ser comparado.
  2. Implementando um objeto comparador

Para a 1º situação você deve conforme a interface criar um método chamado compareTo, o retorno deste método deve ser um int (primitivo) onde deve conter o valor -1 se o objeto comparado foi menor do que o objeto atual, 0 se objeto for igual e 1 se o objeto for maior.

Para a situação 2 você deve fazer uma classe que implemente a interface Comparable como na situação 1.

para realizar a ordenação você deve utilizar um método estático da API Collections o SORT, este método sobrecarregado tem 2 implementações a primeira você passa a list que contém os seus objetos e ele coloca em ordem, lembrando que para ele fazer isto você deve implementar Comparable, caso contrário ele disparará uma exception, e a outra forma é passar a lista e o objeto comparador, desta forma você pode ordenar os seus objetos.

Mais ai vem um detalhe importante com a qual esta semana me deparei, precisei colocar não um só campo do objeto em ordem, mas sim 5 campos do objeto, como fazer isto? depois de pesquisar encontrei a solução a Apache tem uma API Common Collections e BeanUtil (veja as dependências) estas bibliotecas contém funções comuns e uma delas advinhem só, faz exatamente isto, segue um código de exemplo de ordenação por mais de um campo:

List sortFields = new ArrayList();

sortFields.add(new BeanComparator("nome"));
sortFields.add(new BeanComparator("sobrenome"));

ComparatorChain multiSort = new ComparatorChain(sortFields);

java.util.Collections.sort(clientes,multiSort);

O código acima faz a ordenação das lista de objetos clientes pelos campos nome e sobrenome, facilitando assim a ordenação de objetos.

espero que gostem da dica.



2 comentários :