Boa prática em classe que acessa Objeto DAO

Motivado pelo último tópico que abri por aqui, venho perguntar se o que faço na minha classe, que acessa um objeto DAO para recuperar informações da BD, é uma boa prática. Não gosto da referência recursiva à classe Empresa. Aqui está o código do método:

	public void getEmpresa(){
		EmpresaDAO dao = new EmpresaDAO();
		Empresa e = dao.getEmpresa(this.getCod());
		this.setCod(e.getCod());
		this.setFranquia(e.getFranquia());
		this.setNome(e.getNome());
		this.setEmail(e.getEmail());
		this.setSos(e.getSos());
		this.setFtpDir(e.getFtpDir());
		this.setFtpArq(e.getFtpArq());
		this.setFuso(e.getFuso());
		e   = null;
		dao = null;
	}

Obrigado!

Abraços!

Este método está em que classe, no entity Empresa?

Positivo.

Pensei que talvez não fosse necessário, mas vou colocar o código completo da classe, e vc e o pessoal aproveitam para ver se estou pecando em algum outro ponto, além deste.

package br.com.trimbase.skywave.agente;

public class Empresa {
	private Long cod;
	private Franquia franquia;
	private String nome;
	private String email;
	private String sos;
	private String ftpDir;
	private String ftpArq;
	private int fuso;
  
	public Empresa(){
		cod      = 0L;
	    franquia = new Franquia();
	    nome     = "";
	    email    = "";
	    sos      = "";
	    ftpDir   = "";
	    ftpArq   = "";
	    fuso     = 0;
	}

	public void getEmpresa(){
		EmpresaDAO dao = new EmpresaDAO();
		Empresa e = dao.getEmpresa(this.getCod());
		this.setCod(e.getCod());
		this.setFranquia(e.getFranquia());
		this.setNome(e.getNome());
		this.setEmail(e.getEmail());
		this.setSos(e.getSos());
		this.setFtpDir(e.getFtpDir());
		this.setFtpArq(e.getFtpArq());
		this.setFuso(e.getFuso());
		e   = null;
		dao = null;
	}

	public Long getCod() {
		return cod;
	}

	public void setCod(Long cod) {
		this.cod = cod;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Franquia getFranquia() {
		return franquia;
	}

	public void setFranquia(Franquia franquia) {
		this.franquia = franquia;
	}
	
	public void setFranquia(Long codFranquia){
		Franquia f = new Franquia();
		f.setCod(codFranquia);
		f.getFranquia();
		this.setFranquia(f);
		f = null;
	}

	public String getFtpArq() {
		return ftpArq;
	}

	public void setFtpArq(String ftpArq) {
		this.ftpArq = ftpArq;
	}

	public String getFtpDir() {
		return ftpDir;
	}

	public void setFtpDir(String ftpDir) {
		this.ftpDir = ftpDir;
	}

	public int getFuso() {
		return fuso;
	}

	public void setFuso(int fuso) {
		this.fuso = fuso;
	}

	public String getNome() {
		return nome;
	}

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

	public String getSos() {
		return sos;
	}

	public void setSos(String sos) {
		this.sos = sos;
	}
}

Eu faria, de imediato, algumas alterações

  1. Esse construtor setando “new Franquia()” pode gerar um problema… como vc irá persistir uma franquia “nula ou branca” no banco?!?
  2. Acho que o método “getEmpresa” tem a finalidade de “buscar uma empresa cadastrada no banco”, correto? Neste caso, eu o colocaria no DAO referente a Empresa, ou em um DAO genérico… não sou fã dessa abordagem de colocar métodos dentro das classes que representam entidade…
  3. A parte de franquia é de responsabilidade da entidade Franquia!

[quote=rodrigoallemand]Eu faria, de imediato, algumas alterações

  1. Esse construtor setando “new Franquia()” pode gerar um problema… como vc irá persistir uma franquia “nula ou branca” no banco?!?
  2. Acho que o método “getEmpresa” tem a finalidade de “buscar uma empresa cadastrada no banco”, correto? Neste caso, eu o colocaria no DAO referente a Empresa, ou em um DAO genérico… não sou fã dessa abordagem de colocar métodos dentro das classes que representam entidade…
  3. A parte de franquia é de responsabilidade da entidade Franquia![/quote]

Blz. Acho que entendi.

Os relacionamentos estão assim. Uma Franquia tem uma Empresa que por sua vez, tem um Veículo.

Franquia ------> Empresa -------> Veiculo

A busca começa de baixo para cima. O satélite manda na mensagem a informação de quem é o Veículo. A partir deste “vou subindo” no relacionamento. Então, o relacionamento das classes está desta forma: A classe Veículo tem um atributo Empresa, e a classe Empresa tem um atributo Franquia. Nunca gostei desse relacionamento conceitualmente inverso. Na página WEB os relacionamentos são da seguinte forma: Uma Franquia tem um Set de Empresas e cada Empresa tem um Set de Veiculos. Entretanto não consegui ver uma forma de fazer isso quando a questão é no coletor de dados, onde as informações são buscadas de baixo para cima.

Com relação ao método getFranquia(), eu fazia essa busca no DAO da Empresa, mas eu estava trabalhando com 3 conexões permanentes no pool, quando eu preciso apenas de uma. Achei um desperdício, então bolei essa solução, que usa a mesma conexão criada para encontrar o Veículo para encontrar a Empresa e a Franquia.

Pensei também em resolver isso com JOIN no SELECT (encapsulando em uma view na BD), mas me pareceu que quebraria a Responsabilidade da classe DAO de Veículo se no mesmo SELECT eu buscasse as informações da Franquia e da Empresa e preenchesse os objetos referentes. Sem contar que dessa forma, eu deveria ter um atributo Empresa e Franquia dentro da classe Veiculo, o que para mim, só aumentaria a má (péssima) prática.

Vale notar que trabalho com uma base de dados legada (pessimamente modelada), que já era para ter sido substituida desde maio, mas a empresa onde trabalho resolveu terceirizar este serviço para ver se andava mais rápido (sou o único programador da empresa).

Sou novo no mundo das boas práticas e quero aprender cada vez mais. Por isso conto com a sua colaboração e com a colaboração do povo GUJ!

Abraços

E aí Rodrigo? Any ideas? Anybody? =)
Quero melhorar meus códigos. =)

Abraços!

Eu sempre divido as coisas assim, levando-se em consideração, as classes de dominio (Domain Model).

–> BusinessObject (BO) --> Repository --> DAO --> Entity

onde:

BO: Regra de negócio propriamente dita, onde vc pode chamar mais de um Repositorio. Nela ficarão métodos do tipo VerificarPedidosExpedidos, recuperarPedido, cancelarPedido, incluirDetalhePedido. Algumas pessoas chamam classes deste fim de Manager, Negocio, Business e coisas que remetem a Regra de Negocio.

Repository: Interface de uma área do seu sistema, as vezes por entidade, outras por unidade de negocio do seu sistema. Por exemplo, se vc tem uma estrutura assim Pedido tem DetalhesDePedido, vc tem um PedidoRepository que fará as rotinas com as entidades de Pedido e DetalhePedido. Métodos dessa interface são getPedidoByState, update, save, delete (estes três ultimos, se possivel, extendendo um repositorio genérico)

DAO: A implementação de um Repositorio. Aqui ficará a sua rotina de acesso a banco propriamente dita, seja ela Hibernate, JPA, iBATIS, JDBC, o que seja. Segue a mesma lógica do Repositorio, só que fazendo a sua implementação.

Entity: os POJOs referentes a sua classe, com os respectivos métodos get e set. Nestes, quando possivel alguma regra referente somente a entidade, eu gosto de colocar, como isChamadoValido, checando algumas regras de negocio.

Bem, é mais ou menos isso que eu coloco nos sistemas. É um conceito simples, funcional, bem dividido e facil de se entender em futuras manutenções.

de vez em quando eu vejo algum codigo com

PessoaService srv = new PessoaService()

essas classes ‘services’ é a mesma coisa que um BO?

[quote=celso.martins]E aí Rodrigo? Any ideas? Anybody? =)
Quero melhorar meus códigos. =)

Abraços![/quote]

O problema pricipal do seu codigo é o “getEmpresa”.
Um objeto não deve ter um me´todo que se procura a si proprio. Isso não faz nenhum sentido.
O codigo dentro desse metodo pega uma empresa e depois copia-a para a empresa this.
Ora, para queê serve isto ? A empresa retornada já é uma empresa usável.

Se Empresa é criado apenas dentro do DAO não precisa inicializar os atributos no construtor.
Se é criada fora do DAO, crie um contrutor compreensivel ou alguns métodos estaticos que o ajudem
a cria entidade. Por exemplo

Franquia f = new FranqiaDAO().getFranquia(codigoFranquia);
Empresa e = Empresa.newInstance("nome da empresa", f);

new EmpresaDAO().save(e);

[quote=Henrik]de vez em quando eu vejo algum codigo com

PessoaService srv = new PessoaService()

essas classes ‘services’ é a mesma coisa que um BO?[/quote]

Eu editei o meu ultimo post um pouco antes do seu… mas é isso mesmo… qualquer nome que remeta a Regra de negócio…

Uma outra boa prática é colocar uma factory ai ou usar a injeção de dependencia para isso…

Ficaria algo assim:

//Fazendo um método para cada Service PessoaService srv = ServiceFactory.getPessoaService();
ou

//Fazendo uma inferencia na lista de Services disponiveis por Entidade PessoaService srv = ServiceFactory.getServiceFor(Pessoa.class);
ou

//Injetando, neste caso com o Spring InputStream is = new FileInputStream("beans.xml"); BeanFactory factory = new XmlBeanFactory(is); PessoaService srv = (PessoaService) factory.getBean("pessoaService");

Maneiras, existem várias!

[quote=rodrigoallemand]Eu sempre divido as coisas assim, levando-se em consideração, as classes de dominio (Domain Model).

–> BusinessObject (BO) --> Repository --> DAO --> Entity

onde:

BO: Regra de negócio propriamente dita, onde vc pode chamar mais de um Repositorio. Nela ficarão métodos do tipo VerificarPedidosExpedidos, recuperarPedido, cancelarPedido, incluirDetalhePedido.

Repository: Interface de uma área do seu sistema, as vezes por entidade, outras por unidade de negocio do seu sistema. Por exemplo, se vc tem uma estrutura assim Pedido tem DetalhesDePedido, vc tem um PedidoRepository que fará as rotinas com as entidades de Pedido e DetalhePedido. Métodos dessa interface são getPedidoByState, update, save, delete (estes três ultimos, se possivel, extendendo um repositorio genérico)

DAO: A implementação de um Repositorio. Aqui ficará a sua rotina de acesso a banco propriamente dita, seja ela Hibernate, JPA, iBATIS, JDBC, o que seja. Segue a mesma lógica do Repositorio, só que fazendo a sua implementação.

Entity: os POJOs referentes a sua classe, com os respectivos métodos get e set. Nestes, quando possivel alguma regra referente somente a entidade, eu gosto de colocar, como isChamadoValido, checando algumas regras de negocio.

Bem, é mais ou menos isso que eu coloco nos sistemas. É um conceito simples, funcional, bem dividido e facil de se entender em futuras manutenções.[/quote]

Creio ter entendido a filosofia da arquitetura apresentada por você. Vou procurar me aprofundar um pouco mais nesses conceitos, antes de tentar aplica-los numa futura e inevitável refatoração.

Entretanto gostaria de saber, nessa modelagem atual, há erro conceitual? Mesmo eu tendo que seguir esse caminho de baixo para cima?

Devo lembrar que é um aplicativo “console” que fica rodando indefinidamente no servidor. Não é programação WEB.

No seu exemplo, Pedido teria um Set de DetalhesDoPedido, correto? Talvez seja o mesmo que eu usar ItemDoPedido, como é o meu costume. Deve ser uma página WEB. Talvez a minha abordagem de “cima para baixo” na página que acessa as informações esteja correta, talvez eu só precise refatorar para essa arquitetura de BOs, VOs, Repository, etc. Este último é novidade para mim, os outros eu já tinha ouvido falar.

Acho que vou abrir outro tópico para tirar uma dúvida minha sobre modelagem dessas classes BOs e VOs que já me persegue há algum tempo.

Obrigado!

[quote=sergiotaborda][quote=celso.martins]E aí Rodrigo? Any ideas? Anybody? =)
Quero melhorar meus códigos. =)

Abraços![/quote]

O problema pricipal do seu codigo é o “getEmpresa”.
Um objeto não deve ter um me´todo que se procura a si proprio. Isso não faz nenhum sentido.
O codigo dentro desse metodo pega uma empresa e depois copia-a para a empresa this.
Ora, para queê serve isto ? A empresa retornada já é uma empresa usável.

Se Empresa é criado apenas dentro do DAO não precisa inicializar os atributos no construtor.
Se é criada fora do DAO, crie um contrutor compreensivel ou alguns métodos estaticos que o ajudem
a cria entidade. Por exemplo

Franquia f = new FranqiaDAO().getFranquia(codigoFranquia);
Empresa e = Empresa.newInstance("nome da empresa", f);

new EmpresaDAO().save(e);

[/quote]

Amigo, chegaste ao meu ponto central. Você disse com certeza algo que eu tinha “quase certeza” de que estava errado.

Como eu faria? Chamaria de outro objeto, o getEmpresa() diretamente do EmpresaDAO?

Vou usar um exemplo direto, para chegar até o objeto que necessita recuperar as informações de outro. A classe Skywave recebe a mensagem dos servidores da Skywave e procura o veiculo dessa forma:

O código abaixo está dentro de um laço FOR, que percorre as mensagens já recebidas do servidor (O servidor descarrega em um único XML toda a fila de mensagens pendentes).

        		veiculo = new Veiculo();
				veiculo.setEmail(msgSkywave.getTerminal()[i]);
				veiculo.getVeiculo();
	        	if (veiculo.getCod() == 0){
	        		System.out.println("[Veiculo nao encontrado - id: " + msgSkywave.getId()[i] + "]");
	        		continue;
        		}

Neste trecho, talvez eu devesse utilizar isso?

    VeiculoDAO dao = new VeiculoDAO();
    Veiculo v = dao.getVeiculo();

Obrigado!

[quote=celso.martins]Entretanto gostaria de saber, nessa modelagem atual, há erro conceitual? Mesmo eu tendo que seguir esse caminho de baixo para cima?
[/quote]

Erro conceitual, ao meu ver, só o fato já citado da classe referenciar e buscar dados dela mesma… Apesar que nós só vimos uma classe, e não a “linha” até chegar a ela…

Isso é independente… vc poderia usar este conceito em Web, Desktop ou numa aplicação StandAlone, como a sua.

[quote=celso.martins]
No seu exemplo, Pedido teria um Set de DetalhesDoPedido, correto? Talvez seja o mesmo que eu usar ItemDoPedido, como é o meu costume. Deve ser uma página WEB. Talvez a minha abordagem de “cima para baixo” na página que acessa as informações esteja correta, talvez eu só precise refatorar para essa arquitetura de BOs, VOs, Repository, etc. Este último é novidade para mim, os outros eu já tinha ouvido falar.

Acho que vou abrir outro tópico para tirar uma dúvida minha sobre modelagem dessas classes BOs e VOs que já me persegue há algum tempo.

Obrigado![/quote]

Essa abordagem é correta

Pedido tem um ou mais itens de Pedido, então Pedido tem um atributo Set ou coisa do genero
Já item de pedido está ligado a apenas um pedido, com isso ItemPedido tem um atributo Pedido.
Essa relação de inversão entre duas entidades que estão ligadas existe sim!

[quote=rodrigoallemand][quote=celso.martins]Entretanto gostaria de saber, nessa modelagem atual, há erro conceitual? Mesmo eu tendo que seguir esse caminho de baixo para cima?
[/quote]

Erro conceitual, ao meu ver, só o fato já citado da classe referenciar e buscar dados dela mesma… Apesar que nós só vimos uma classe, e não a “linha” até chegar a ela…
[/quote]

Disso eu tinha quase certeza. =)

Disse isso, pois achei importante saber que a linha normal:

Usuário Loga -> Sistema identifica a que franquia pertence e instancia o objeto Franquia desse usuário -> No objeto Franquia, existem o Set de Empresas -> Em cada Empresa, existe o Set de Veiculos -> Em cada Veiculo existe o Set de Leituras limitado, por default, a 30, pois são as Leituras mais vistas pelos nossos clientes.

É diferente do “Aplicativo Coletor”, que é:

Coletor busca informações nos servidores Skywave -> Sistema identifica a qual Veiculo cada mensagem se relaciona -> Sistema identifica a Empresa -> Sistema identifica a Franquia.

A lógica é inversa.

Devo informar que apenas a informação de “quem é” o Veiculo é de suma importância para a gravação correta da leitura GPS. Entretanto as informações de Empresa e Franquia são importantes para, mais rapidamente, identificarmos problemas com clientes. Este coletor gera um output com essas informações.

[quote=celso.martins]
No seu exemplo, Pedido teria um Set de DetalhesDoPedido, correto? Talvez seja o mesmo que eu usar ItemDoPedido, como é o meu costume. Deve ser uma página WEB. Talvez a minha abordagem de “cima para baixo” na página que acessa as informações esteja correta, talvez eu só precise refatorar para essa arquitetura de BOs, VOs, Repository, etc. Este último é novidade para mim, os outros eu já tinha ouvido falar.

Acho que vou abrir outro tópico para tirar uma dúvida minha sobre modelagem dessas classes BOs e VOs que já me persegue há algum tempo.

Obrigado![/quote]

[quote]Essa abordagem é correta

Pedido tem um ou mais itens de Pedido, então Pedido tem um atributo Set ou coisa do genero
Já item de pedido está ligado a apenas um pedido, com isso ItemPedido tem um atributo Pedido.
Essa relação de inversão entre duas entidades que estão ligadas existe sim![/quote]

Dessa inversão de relacionamento eu tbm não sabia. É realmente necessário em ItemDePedido haver um atributo se referenciando ao Pedido? Apenas o Set de ItemDePedido em Pedido não seria suficiente? Gostaria de entender melhor isso.

Obrigado!

Isso depende da sua necessidade… se não utiliza isso, beleza! ranca fora que é uma query a menos!
Se for o caso do set tb, ranca geral!!!
Coloque apenas o que vc realmente for usar…

Isso depende da sua necessidade… se não utiliza isso, beleza! ranca fora que é uma query a menos!
Se for o caso do set tb, ranca geral!!!
Coloque apenas o que vc realmente for usar…[/quote]

Opa… qualquer semelhança com XP seria mera coincidência? =)

Estou lendo o livro do Kent Beck agora. Cheguei na parte da solução hj pela manhã. =)

Agora e aquela questão da lógica da WEB e do meu coletor. Onde a informação inicial da primeira (Franquia) é diferente da informação inicial da última (Veiculo)?

Abraços!

[quote=celso.martins]

O código abaixo está dentro de um laço FOR, que percorre as mensagens já recebidas do servidor (O servidor descarrega em um único XML toda a fila de mensagens pendentes).

        		veiculo = new Veiculo();
				veiculo.setEmail(msgSkywave.getTerminal()[i]);
				veiculo.getVeiculo();
	        	if (veiculo.getCod() == 0){
	        		System.out.println("[Veiculo nao encontrado - id: " + msgSkywave.getId()[i] + "]");
	        		continue;
        		}

Neste trecho, talvez eu devesse utilizar isso?

    VeiculoDAO dao = new VeiculoDAO();
    Veiculo v = dao.getVeiculo();

Obrigado![/quote]

deviar ser algo como


VeiculoDAO dao = new VeiculoDAO ();

for ( int i ; ..... ){
// encontra baseado no email
// se não encontrar retorna null
Veiculo v = dao.findByEmail(msgSkywave.getTerminal()[i]));

if (v==null){
 //não encontrado
System.out.println("[Veiculo nao encontrado - id: " + msgSkywave.getId()[i] + "]");
	        		continue;
} 

}

[quote=sergiotaborda][quote=celso.martins]

O código abaixo está dentro de um laço FOR, que percorre as mensagens já recebidas do servidor (O servidor descarrega em um único XML toda a fila de mensagens pendentes).

        		veiculo = new Veiculo();
				veiculo.setEmail(msgSkywave.getTerminal()[i]);
				veiculo.getVeiculo();
	        	if (veiculo.getCod() == 0){
	        		System.out.println("[Veiculo nao encontrado - id: " + msgSkywave.getId()[i] + "]");
	        		continue;
        		}

Neste trecho, talvez eu devesse utilizar isso?

    VeiculoDAO dao = new VeiculoDAO();
    Veiculo v = dao.getVeiculo();

Obrigado![/quote]

deviar ser algo como

[code]

VeiculoDAO dao = new VeiculoDAO ();

for ( int i ; … ){
// encontra baseado no email
// se não encontrar retorna null
Veiculo v = dao.findByEmail(msgSkywave.getTerminal()[i]));

if (v==null){
//não encontrado
System.out.println("[Veiculo nao encontrado - id: " + msgSkywave.getId()[i] + “]”);
continue;
}

}
[/code][/quote]

Obrigado Sergio! Matou a pau a minha dúvida!!

Essa refatoração começarei amanhã de manhã.