DAO com hibernate

Pessoal,
estou tentando projetar a persistencia de uma app usando o padrão DAO, como explicado em http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html.
Mas não estou conseguindo entender as diferenças/semelhanças entre o objeto de negócio é o que ele chama de “objeto de transferência”. Esse seria, pelo que diz o artigo, o objeto que o DAO concreto usa para transferir dados da BD para a ram.
Aí eu pergunto: o hibernate não faz essa “transferencia” diretamente a partir do objeto de negócio? Eu realmente preciso implementar uma nova classe aqui, ou posso usar a própria classe de negócio?
E se precisar implementar, no que ela difere da classe de negócio?
Para exemplificar a minha dúvida, suponhamos uma classe forum simplificado assim:

public class ForumSimples
{
   private String nome;
   private ArrayList linhasDeDiscussao;

//gets & sets...
}

class LinhaDeDiscussao 
{
   private String assunto;
   private ArrayList mensagens;
//...
}

class Mensagem
{
    private String texto;
    private Date dataDeCriacao;
    private Usuario autor;
//....
}

Bem, até onde eu entendi, com os mapeamentos corretos, basta eu dar um sessao.saveOrUpdate(meuForum) no hibernate que ele grava tudo, inclusive as linhas e as mensagens, não é? O mesmo valendo na hora de recuperar, certo?
Então eu não consigo compreender a necessidade de ter uma outra classe, por exemplo, ForumSimplesTransfer. Pelo que vejo, bastaria o meu DAO referenciar o próprio objeto ForumSimples que solicitou a gravação. Ou não?
Aliás, mesmo que eu usasse jdbc puro para persisir os objetos, eu ainda não conseguiria ver utilidade para esse tal TransferObject… :cry:
Alguém poderia me esclarecer?

Objeto de transferência é usado para comunicar entre dois tiers da aplicação.

O servidor de aplicação (EJB) rodando em uma máquina e o servidor web em outra. Nesse caso é interessante usar DTOs para a comunicação entre eles.

Estendendo a explicação do louds, imagine que você tem um objeto de negócio com muitas linhas, cheios de métodos inteligentes. Assim, quando é serializado, fica um pouco grande.
Se os servidores das camadas da sua aplicação estivessem fisicamente distantes (em máquinas diferentes), pode ser interessante usar um objeto mais leve que guarde apenas dados, sem lógica de negócio. Assim a transferencia do objeto mais leve entre as camadas fica mais rápida e alivia um pouco a carga dos servidores e da rede.

Mas uma situação assim é rara. Pessoas usam TOs adoidado porque são … maníacas por reescrever código burro e sem utilidade \o/

Um pouco incorreta a explicação, LIPE. Objetos serializados ficam grandes quando contém muitas referências a outros objetos distintos e estes, por sua vez, a outros objetos ou a algum objeto “gigante” - como uma array de 5Mb, por exemplo.

Métodos não interferem no tamanho do objeto serializado, mas afetam o cálculo do serialVersionUID.

Voltando ao assunto principal: use Transfer Objects somente quando você tiver um grafo gigante e for usar meia dúzia de propriedades.

Agora entendi! :smiley: Então o DTO só é necessário se a estrutura do objeto for muito grande, caso contrário, usa-se o próprio objeto como DTO.
Então o meu raciocínio estava correto… pensei que não estava conseguindo enxergar algo, por causa do sono… :wink:
Agradeço a todos que responderam. Valeu mesmo, pessoal.
Até.

Bem, DTOs sao aglomerados de dados de origens distintas que voce transporta entre sua aplicaçao. Ate ai tudo bem.
Porem considerando-se uma estrutura web. O JSP envia a requisiçao para o servlet, o servlet direciona para o local adequado, que faz seu tratamento de dados e regras de negocio, que por sua vez usa a a camada de persistenci para determinado fim.
Suponha-se que esse determinado fim seja uma consulta. A camada de negocio recupera os dados que necessita e precisa apresentar na view alguns deles.
Nao vejo como nao usar DTO para passar os dados necessarios para o servlet ou para o JSP.
Por exemplo eu executo as consultas e validaçoes que necessito e retorno uma Collection com os dados para a view. Como nao usar DTO para nao transferir um monte de objetos e dados que eu nao vou utilizar na view?
Ou esta Collection que eu retorno nao e um DTO e eu to falando besteira?

Rafael,
não sei se a minha dúvida inicial tinha ficado clara para vc. SE vc olhar o diagrama do DAO do artigo que eu citei, vai ver duas classes: a classe de negócio (no meu mini exemplo, a ForumSimples) e uma classe de Transferência (ForumSimplesTransfer???). A minha dúvida era se eu não poderia usar o próprio objeto do tipo ForumSimples como DTO, ao invés de criar uma outra classe só para isso.
Pelo que entendi das respostas dos colegas, posso sim, e só teria sentido criar uma nova classe se hovesse uma diferença significativa entre a estrutura da classe original de negócio e os dados que precisassem ser persistidos/recuperados.
Então, não é que não tem DTO, é que ele acaba sendo o próprio objeto de negócio.
Se eu entendi tudo errado, por favor, me corrijam!
Valeu.

Rafael, você pode retornar os objetos de domínio sem o menor problema.

Um DTO contem somente o necessario que o tier (não confundir com layer) seguinte precisa.

Por exemplo, um session bean retorna os pedidos em aberto de um cliente, temos muitas entidades envolvidas nisso… cliente, pedido, historico do pedido e outros trantos, mas o DTO pode ser simplesmente:

public class PedidosEmAbertoDTO {
   static class DetalhePedidoDTO {
     String descricaoCurta;
     long pkPedido;
   }
   String usuario;
   long usuarioPK;
   DetalhePedidoDTO[] detalhes;
}

Veja que todas informações estão agregadas na forma mais compacta possivel para transmissão on-wire e não lembram mais o seu modelo de entidades original.

Como assim, retornar todos os objetos que eu utilizar em um determinado processo?Retornar uns 30 objetos sendo que vou utilizar um atributo de cada?

Minha dúvida é se pegar os objetos do meu domínio e montar uma Collection com os atributos que eu necessito para enviar para outra camada caracteriza um DTO, ou se DTO caracterizaria-se por um Objeto sem nenhuma função no domínio, que não representa nenhuma entidade e serve apenas pra transportar os dados condensados.

Essa regra de objetos com muitas referencias vale para os objetos muito
"cascateados".
ex:


class Funcionario
{
    Departamento dep = null;
}

class Departamento
{
   Filial filial = null;
   Funcionario chefe = null;
}

class Filial
{

}

E assim vai…
São objetos pequenos, mas que podem atingir um nivel de cascateamento muito grande.
Mas percebam que todos os objetos tem referencia NULL, ou seja, serão instanciados somente os atributos que forem necessarios.
Mas se eu quiser ver a filial de um funcionario terei que instanciar outros objetos.ex:

String nomeFilial = funcionario.getDepartamento().getFilial().getNome();

Fica flexivel, mas neste caso, fica melhor um DTO ?

Entendi mister_m, valeu :smiley:

jprogrammer, se você precisa fazer isso no seu código tem alguma coisa errada. Pelo menos foi o que eu entendi e concordei depois de ler isso aqui:
http://c2.com/cgi/wiki?LawOfDemeter

Dei uma lida e achei interessante.
Mas aqui é uma representação “relacional” nos objetos.
Acredito que muita gente usa alguma coisa como esta quando usa o hibernate ou outra coisa que faz mapeamento OOXRelacional.

Isto é uma agregação de objetos.
Então ao inves de agregar eu teria que implentar a interface do objeto.
Fica um pouco estranho.
Isso traz a perda da flexibilidade.
Imagine quantas interfaces a classe Funcionario teria que implementar para trazer a filial
Isso é um exemplo de uma agragação bastante simples…
Imagine em uma agragação mais complexa.

[quote=LIPE]Pelo menos foi o que eu entendi e concordei depois de ler isso aqui:
http://c2.com/cgi/wiki?LawOfDemeter[/quote]

Um comentário inútil sobre a lei de Deméter é que todo mundo quando lê o paper original pensa: “Cacete, mas como eu vou alterar o atributo do usuário se eu não puder pegar o atributo do usuário?”.

A resposta que é difícil de ver ás vezes é: você não tem que alterar nada, peça ao usuário que a altere.

Mas e se for para pegar o valor do atributo ?

aí eh uma query, não uma mudança :wink:

Mas note uma cosia: Leid e Demeter é como acoplamento e coesão. Você não quer ter muito acomplamento, porque é ruim, mas acoplamento zero também é ruim (causa baixa coesão). Tem que saber dosar as partes :wink:

Mas uma nível de agragação com coloquei acima é coerente ?
Não vejo uma melhor forma para manter a flexibilidade nas queries de objetos.

A coerência vai depender do seu modelo, mas acredito que esteja.

Realmente, se voc~e precisar passar um Funcionario pela rede, é melhor que empacote tudo que vai precisar num DTO só, ao invés de fazer queries cosntantes e caras via RPC.

Então não há problema em usar, por exemplo, os objetos persistentes do Hibernate (aqueles que o Hibernate mapeia diretaemnte com as tabelas do BD) como objetos de negócio?

Não é que eles devam ser usados como objetos de negocio, mas eles podem ter logica sim! Alias, os objetos do hibernate costumam ser atrofiados demais, acabam parecndo estruturinhas de dados em vez de objetos, que tem estado E comportamento.

No site do Calçado tem artigos interessantes sobre isso.

É como o Calçado disse, devemos dosar. Mesma coisa com DTO e o que o louds disse: nao vai mudar de tiers, usa o objeto direto (talvez voce quisesse ter pergutnado isso, se poderia usar o objeto do hibernate e o DTO como o mesmo)! Pra que criar um conjunto de classes paralelo e quase identico ao de suas entidades? A nao ser, claro, que eles sejam remotos (como no ejb2) ou se eles serao serializados e sao muito grandes (como disse o misterm). Ai sim voce usa DTO.

Não é que eles devam ser usados como objetos de negocio, mas eles podem ter logica sim! Alias, os objetos do hibernate costumam ser atrofiados demais, acabam parecndo estruturinhas de dados em vez de objetos, que tem estado E comportamento.

No site do Calçado tem artigos interessantes sobre isso.

É como o Calçado disse, devemos dosar. Mesma coisa com DTO e o que o louds disse: nao vai mudar de tiers, usa o objeto direto (talvez voce quisesse ter pergutnado isso, se poderia usar o objeto do hibernate e o DTO como o mesmo)! Pra que criar um conjunto de classes paralelo e quase identico ao de suas entidades? A nao ser, claro, que eles sejam remotos (como no ejb2) ou se eles serao serializados e sao muito grandes (como disse o misterm). Ai sim voce usa DTO.[/quote]

Então na prática pode ser feito o seguinte?

Camada de Apresentação

/**
 * Este objeto A tem métodos de negócio e atributos que serão mostrados  na tela
**/          
ObjetoA objA = service.recuperaObjetoA(int id);

Camada de Negócio

ObjetoA objA = new ObjetoA();
objA.setId(id);

ADao aDao = new ADao();  /* Abre sessão HIbernate */
aDao.recuperaObjetoA(objA);

Considerando que ObjetoA é também a representação de uma tabela do BD, ou seja, objeto persistente do Hibernate.