sábado, 26 de abril de 2014

Construtores



   Os construtores são utilizados para inicializar uma classe, apesar de serem simples de se utilizar e entender, algumas pessoas tem dúvidas e/ou acabam utilizando sem saber sobre sua existencia, com este post eu pretendo mostrar o conceito de construtor com um exemplo prático. A linguagem utilizada será o Java, os construtores serão utilizados para inicializar um JFrame já com algumas informações da nossa entidade.


Sobre a sintaxe dos construtores:
  • Construtores DEVEM ter o exato nome da classe, lembrando que Java é case sensitive
  • Construtores NUNCA terão retorno, nem mesmo void. Se for colocado algum tipo de retorno ele deixará de ser um construtor e se tornará um metodo normal.
  • Construtores podem ter qualquer visibilidade (public, default, protected ou private) porem construtores private podem dificultar herança (veja a seguir)
 Algumas coisas que você deve saber sobre construtores:
  • Usa-se o comando this() para chamar um construtor sem parametros
  • Usa-se o comando this("construtor") para chamar um construtor que pede uma String como parametro
  • Usa-se o comando super() para chamar o construtor da classe pai que não pede nenhum parâmetro
  • Usa-se o comando super("construtor pai") para chamar o construtor da classe pai que pede uma String como parâmetro.
  • Se você não definir um construtor, será criado um construtor padrão pela JVM: um construtor sem parametros e que apenas chama super()
  •  Todo construtor, por padrão, chama o construtor sem parâmetros da classe pai, então mesmo que você escreva código para isso, está implicito que na primeira linha depois de sua declaração existe o comando super(). O único jeito de alterar isto é você declarar explicitamente a chamada de algum outro consstrutor com this ou super.
  • Pelo item anterior, podemos observar que quando uma classe é instanciada, pelo menos um construtor de cada nivel da hierarquia é chamado até chegarmos no construtor da classe Object (pois nossas classes implicitamente herdam de Object)
  • Se você definir apenas um construtor com visibilidade private, sua classe não poderá ser instanciada fora da própria classe, isto é utilizado no padrão Singleton por exemplo.
A seguir está um exemplo simples de utilização de construtores:
 
  Primeiro eu criei um POJO de cliente:
public class Cliente {
    private String nome;
    private String tel;

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getTel() {
        return tel;
    }

    public void setTel(String tel) {
        this.tel = tel;
    }
} 
  Nada de novo por aqui, uma classe de entidade com dois atributos, 2 getters e 2 setters.
    
  Depois eu criei um JFrame, este JFrame tem dois campos de texto, um para exibir o nome do cliente e outro para exibir o telefone:

  
public class ClienteFrame extends JFrame{
    
    private JTextField txtNome = new JTextField();
    private JTextField txtTel = new JTextField();

    public ClienteFrame() {
        this.setLayout(new GridLayout(4, 1));
        this.add(new JLabel("Nome"));
        this.add(txtNome);
        this.add(new JLabel("Telefone"));
        this.add(txtTel);
        this.setSize(300, 300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public ClienteFrame(Cliente c){
        this();
        this.txtNome.setText(c.getNome());
        this.txtTel.setText(c.getTel());
    }    
    
}
  O JFrame tem dois atributos privados, que são os campos de texto que exibirão as informações. Além destes atributos, a classe ClienteFrame tem dois “métodos” que tem o mesmo nome da classe, estes são os construtores desta classe. O construtor sem argumentos monta o layout no nosso frame, enquanto, o construtor que pede um argumento chama o construtor sem argumentos (para que o layout seja montado) e depois adiciona as informações que recebeu como parametro.

SEMPRE que uma classe é instanciada, seu construtor é chamado. Perceba:
JTextField txt = new JTextField();
Cliente c = new Cliente(); //outro construtor
JTextField txt2 = new JTextField("caixa com texto"); //construtor para inicializar o campo contendo um texto

Para finalizar, vamos instanciar nossa classe ClienteFrame com os dois construtores e ver a diferença:
primeiro instanciamos o Frame sem passar nenhum argumento:

public class Main {
    public static void main (String[] args){
        ClienteFrame frame = new ClienteFrame();
        frame.setVisible(true);
    }
}

o resultado é um frame com os campos em branco, como mostra a figura:



Mas podemos também instanciar nosso frame passando um objeto do tipo Cliente como parâmetro:

public class Main {
    public static void main (String[] args){
        //criamos o objeto parametro:
        Cliente c = new Cliente();
        c.setNome("Nome do cliente");
        c.setTel("2673-9000");
        //passamos o objeto criado para o nosso frame:
        ClienteFrame frame = new ClienteFrame(c);
        frame.setVisible(true);
    }
}

O resultado será:


No momento acredito que isto seja o básico, se tiver qualquer dúvida sobre o assunto deixe nos comentários

quinta-feira, 3 de abril de 2014

Usando triggers para criar logs no MySQL


Há um tempo atrás onde trabalho, surgiu a necessidade de saber quais informações eram inseridas eou alteradas e quando estas alterações ocorriam. O sistema que realizava estas alterações tinha um código extremamente mal escrito, então quanto menos alterações fossem feitas no código, melhor. A solução a que cheguei foi utilizar triggers nas tabelas que necessitavam destes logs.
O tutorial utiliza o MySQL, porém a sintaxe para outros SGBD's é bem similar (se não for igual)
Primeiro temos a tabela que desejamos criar os logs:
create table venda (  
      id int auto_increment primary key,  
      dia datetime,  
      valor float  
);
Até aqui sem novidades, este é apenas o código para criar a hipotética tabela de venda, é nesta tabela onde estão as informações q desejaremos “logar”.
O próximo passo é criar a tabela que armazenará as informações:
create table venda_log (  
      log_id int auto_increment primary key,  
      old_id int,  
      old_dia datetime,  
      old_valor float,  
      new_id int,  
      new_dia datetime,  
      new_valor int,  
      acao varchar(6),  
      usuario varchar(50),  
      hora timestamp  
 );  
Nesta tabela temos um campo de id para chave primaria do log, dois campos para cada campo da tabela Venda, um com o prefixo old e outro com o prefixo new. Temos o campo acao para sabermos o que foi feito na tabela, o campo usuario para sabermos qual usuario (do mysql) fez a alteração e o campo hora para sabermos quando esta alteração foi feita.
Agora temos que criar as triggers que alimentarão esta tabela:
create trigger venda_log_insert after insert on venda  
 for each row  
           insert into venda_log(old_id, old_dia, old_valor, new_id, new_dia, new_valor, acao, usuario, hora)   
                     values(null,null,null, new.id, new.dia, new.valor, 'INSERT', user(), now());  
Se você nunca criou uma trigger pode estranhar o código acima, mas é mais simples do que parece:
  • create trigger = código para criar a trigger.
  • venda_log_insert = nome da triger.
  • after = tempo de execução da trigger. Before para executar a trigger antes do comando que causou seu disparo e after para executar a trigger depois do comando que causou seu disparo.
  • insert = o evento que dispara a trigger, poderia ser por exemplo update ou delete
  • venda = a tabela a que a trigger está associada. Esta trigger por exemplo, será disparada quando acontecer um insert na tabela venda.
  • for each row = indica que o corpo da trigger começou, o que vem depois disso é o que de fato a trigger faz.

Outro detalhe importante sobre a trigger é a utilização de “new”, dentro da trigger temos variaveis que representam os campos (da tabela indicada depois do on) antes e depois da alteração. Para utilizarmos o campo antes, usamos old.nome_do_campo e para o campo depois da alteração usamos new.nome_do_campo.
Em triggers de insert, não temos os campos old pois antes da execução do comando a linha ainda não existe. Em triggers de delete não temos os campos new pois não existe linha depois da execução do comando e em triggers do tipo update temos os dois tipos de campo.
O que esta trigger faz então é simples, pega os valores que foram inseridos na tabela indicada e loga eles em uma tabela, informando também o usuario e a hora do acontecimento. Para deixarmos o log completo vamos criar uma trigger para delete e uma para update:
 create trigger venda_log_update after update on venda  
 for each row  
      insert into venda_log(old_id, old_dia, old_valor, new_id, new_dia, new_valor, acao, usuario, hora)   
                values(old.id, old.dia ,old.valor, new.id, new.dia, new.valor, 'UPDATE', user(), now());  
 create trigger venda_log_delete after delete on venda  
 for each row  
      insert into venda_log(old_id, old_dia, old_valor, new_id, new_dia, new_valor, acao, usuario, hora)   
                values(old.id, old.dia ,old.valor, null, null, null, 'DELETE', user(), now());  

Os logs estão prontos, para testar vamos realizar algumas operações na nossa tabela:

 insert into venda (dia, valor)values ('2014/03/09 19:43:00',137.00);  
 update venda set valor = 777 where id = 1;  
 delete from venda where id = 1;  

Ao executarmos um select na nossa tabela de log temos 3 linhas:

A primeira linha nos mostra que as 19:45 foi feito um insert, os campos com prefixo new dizem quais valores foram inseridos. A segunda linha nos diz que às 19:49 os valores de uma venda foram alteradas, o valor antigo da venda era 137 e o novo valor passou a ser 777. A ultima linha mostra que havia uma venda com os valores mostrados no old, mas ela foi deletada.
Esta é apenas uma das maneiras de se criar um log em seu banco de dados, se tiver sugestões, críticas, opiniões ou quaisquer pensamentos aleatórios, comente ^^