Como usar Transfer Object?

113 respostas
J

eu tava lendo alguns textos que falavam de transfer object, e eu vi a implementação dele…ele parece ser um javabean…é isso mesmo?
qual a diferença para um javabean?

Esso foi um dos sites q eu vi:
http://java.sun.com/blueprints/corej2eepatterns/Patterns/TransferObject.html

113 Respostas

T

http://www.guj.com.br/posts/list/28219.java

X

http://www.guj.com.br/posts/list/24281.java

Acho que já dá pra ajudar! :wink:

J

no meu caso eu tenho um servlet(controller) um bo e um dao(ambos model)…
eu quero pegar alguns dados do meu banco de dados…
então eu acesso o meu bo e depois o meu dao. O dao cria o TO e retorna para o bo que retorna para o meu servlet para que os dados possam ser exibidos…
se eu não usar um TO qual seria a alternativa?

R

Para que o DAO precisa criar o TO?
Retorne as informações que precisa para o BO e do BO para o Controller.

J

utilizar um TO é o modelo de implementação de DAO que está no corepatterns da sun…
qual seria sua sugestão?
usar uma collection?

_

Leia novamente o segundo link que o Thiago Senna postou.

Ele serve para encapsular diversas chamadas de rede numa só. Então te pergunto: seu banco de dados está fisicamente num lugar distante do local físico onde os servlets se encontram? Não? Então não precisa dessa gambiarra horrível \o/

R

É só uma das possibilidades de implementação do DAO. E mesmo no catálogo dos TO, eles são bem enfatizados o uso junto com EJB´s(geralmente aplicações distribuídas). Uma das principais vantagens de um TO é reduzir o tráfego de rede.
Você não precisa criar um objeto alienígena deste só pra passar de uma camada pra outra. Retorne uma Collection, ou o próprio objeto.

P

Que são belas gambiarras para tornar EJB algo menos horrível.

Você não precisa de DTOs fora de um ambiente distribuído.

J

então eu transfiro data entre as classes através de retorno do método mesmo?
Ex.:

dentro do meu servlet ficaria assim:
List a = meuBO.getData();

dentro do meu método getData() do bo ficaria assim:
return meuDAO.getDATA();

e dentro do método getData() do meu DAO teria:

return list;

acho q ficou um pouco confuso isso q eu escrevi…mas… :roll:

P

Seu objeto de negócios (dica: evite esse padrão de nome de classes) acessa o DAO?

T

Haáaaaaaaaaaaaaaaaaaaa!!!

Para com isso… vc me obrigou a me lembrar do dia que exibe uma arquitetura como esta como meu maior trunfo no meu projeto de final de curso!

JDeveloper, eu quando comecei aqui no guj tinha a mesma dúvida que você! Eu li o mesmo livro q vc, e cheguei nas mesmas conclusões q vc e o pior, cheguei nesta mesma arquitetura! Vc dúvida?? Veja isto entaum uma bagunça que eu tinha aprontado aqui no fórum!

http://www.guj.com.br/posts/list/21002.java
http://www.guj.com.br/posts/list/21007.java
http://www.guj.com.br/posts/list/21017.java

Então, como vc não está trabalhando em um ambiente distribuído, esqueça o TO, esqueça o BO e mandem todos eles para a pqp!

Ao invés de vc sair criando classes como AlunoTO e AlunoBO, cria uma classe aluno logo de uma vez! É muito mais elegante e mais fácil. Ele guarda dados referente ao objeto e ainda encapsula as lógicas de negócio!

Com certeza, as únicas coisas que serão úteis no seu projeto são os DAO’s, e dependendo do tamanho do projeto, um AbstractFactory ou Façade já poderá ajudar bastante!

Agora pegue um pedaço de papéu e escreva 100x “Eu nunca vou usar DTO em sistemas não distribuídos!”

Abraços!
Thiago Senna

J

pcalcado:
Seu objeto de negócios (dica: evite esse padrão de nome de classes) acessa o DAO?

qual o problema com o nome?

Eu tenho que fazer um cadastro via web. Então o usuário preenche os campos e dá um submit.
O meu servlet pega a requisição e chama o meu bo para validar campos e etc. O bo então chama o dao para persistir os dados, caso os mesmos sejam válidos…
isso não está correto?

J

valeu pelas sugestões de leitura… não vou mais usar dto…

:smiley:

Só uma coisa… vc disse pra esquecer o bo…mas não é importante ter uma camada de negócios?
o código fica bem mais organizado?

Abraços

P

jdeveloper:

qual o problema com o nome?

Eu tenho que fazer um cadastro via web. Então o usuário preenche os campos e dá um submit.
O meu servlet pega a requisição e chama o meu bo para validar campos e etc. O bo então chama o dao para persistir os dados, caso os mesmos sejam válidos…
isso não está correto?

Funciona? Então está correto.

Só que tudo pode ser melhorado,e quanto mais você se preocupar com design do seu sistema, menos chance de virar noite dando manutenção em bugs bizarros.

Vamos devagar, do que se trata sua aplicação?

W

Eu gosto de usar DTO nas minhas arquiteturas, sendo elas distribuidas ou não, por exemplo para montar frameworks vc precisa utilizar um DTO para transferir os dados de uma camada para outra abstraindo assim por exemplo qual a interface que vc utiliza e deixando a regra de negocio limpa… utilizando apenas seus BO na camada de negócio não levando ele para a camada de interface…

P

wellmattos:
Eu gosto de usar DTO nas minhas arquiteturas, sendo elas distribuidas ou não, por exemplo para montar frameworks vc precisa utilizar um DTO para transferir os dados de uma camada para outra abstraindo assim por exemplo qual a interface que vc utiliza e deixando a regra de negocio limpa… utilizando apenas seus BO na camada de negócio não levando ele para a camada de interface…

Aí você faz:

class Usuario{
 private String nome = null;
 private String endereço = null;
 private int idade = 0;

  //gets e sets
}

E tem um DTO/TO/VO:

class UsuarioVo{
 private String nome = null;
 private String endereço = null;
 private int idade = 0;

  //gets e sets
}

Exatamente igual? Para que?

Para usar frameworks decentes (ou até indecentes como Struts) você não rpecisa de VO. Aliás, você só rpecisa deles numa arquitetura altamente distribuída (que as blueprints do JEE sempre prezam, mas que quase nunca acotnece no mundo real).

O que você chama de montar frameworks?

J

É o seguinte:

Eu tenho q fazer um sistema que faz a inscrição de um usuário online.
Então ele tem basicamente que preencher um cadastro pessoal e de acordo com o tipo de opcao de inscricao q ele escolhe o sistema exibe uma ou outra opção nas telas.

Eu pensei em fazer o seguinte:

Usar um jsp como minha camada de apresentação.
Usar um servlet como controlador.
Usar um BO e um DAO como meu model.

Então o usuário preenche o cadastro(jsp) e envia para o servlet. Esse servlet pega os dados do usuário, armazena em um objeto e envia para a minha camada de negócios para basicamente validar campos.
Se os dados digitados pelo usuário estiverem corretos eu passo esse objeto para a minha camada de negócios para q ele possa ser persistido.

Entendeu?

Isso não está correto?

_

Está correto. E basta um objeto Aluno, um AlunoDAO e um CadastroServlet para isso :smiley:

class CadastroServlet {
    public void execute() {
        Aluno aluno = new Aluno();
        // popula o objeto aluno com os dados da request

        if( !aluno.validate() ) {
            // redireciona de volta com os error
            return;
        }

        AlunoDAO dao = new AlunoDAO();
        dao.save( aluno );
        // ou quem sabe
        aluno.save(); // aluno que chama o DAO
    }
}
J
LIPE:
Está correto. E basta um objeto Aluno, um AlunoDAO e um CadastroServlet para isso :D
class CadastroServlet {
    public void execute() {
        Aluno aluno = new Aluno();
        // popula o objeto aluno com os dados da request

        if( !aluno.validate() ) {
            // redireciona de volta com os error
            return;
        }

        AlunoDAO dao = new AlunoDAO();
        dao.save( aluno );
        // ou quem sabe
        aluno.save(); // aluno que chama o DAO
    }
}

não seria melhor criar mais uma classe para validar os dados...ao invés de validar os dados dentro do servlet...?

_

Existem diversas maneiras de validar dados :smiley: escolha a sua hehe

Eu gosto de usar strategy:

class Aluno {
    private ValidationStrategy validationStrategy;

    public boolean validate() {
        validationStrategy.validate( this );
    }
}

A implementação de ValidationStrategy varia.

K

Uma pergunta.
Qual a diferença dos dois? (Aluno, AlunoVO) ??
Por acaso o Aluno tem regra? o aluno faz persistência?
Porque no meu VO eu não deixo assim:

class UsuarioVo{
 public String nome = null;
 public String endereço = null;
 public int idade = 0;

}

Assim deixando a minha classe “mais leve” pois não tenho métodos para serem persistidos?

_

Serialize uma classe com 10 métodos e outra com 100 métodos e compare os tamanhos dos arquivos. Se o “overhead da sua rede” for grande demais, use VO :smiley:

T

jdeveloper:
Só uma coisa… vc disse pra esquecer o bo…mas não é importante ter uma camada de negócios?
o código fica bem mais organizado?

Vc precisa saber trabalhar com sua camada de negócio, não com o Desgin Pattern Business Object. :wink:

No dia a dia, vc vai ver que o pessoal nem fala em BO, eles falam logo classes de negócio.

Por exemplo, no exemplo que o Lipe passou, a classe Aluno possui um método validate! E vc perguntou se não seria melhor criar uma outra classe para cuidar da validação.

Isso vai do seu gosto, mas já que está usando OO, nada melhor do que o próprio aluno validar seus próprios dados! :wink:

Voltado ao assunto BO, a classe Aluno seria equivalemente a classe AlunoBO. Subtende-se que a classe Aluno é a classe de negócio e acabo! Business Object é um design pattern que até hoje eu naum sei pq criaram ele!

J

Thiago Senna:

Voltado ao assunto BO, a classe Aluno seria equivalemente a classe AlunoBO. Subtende-se que a classe Aluno é a classe de negócio e acabo! Business Object é um design pattern que até hoje eu naum sei pq criaram ele!

Entendi o q vc quer dizer…
Mas eu to pensando em fazer uma classe CadastroServlet, uma AlunoBean, uma AlunoBO e uma AlunoDAO…

assim a classe q vc chamou de Aluno ficaria só pra armazenar os dados do aluno(AlunoBean).

o q vc acha?

T

jdeveloper:
Thiago Senna:

Voltado ao assunto BO, a classe Aluno seria equivalemente a classe AlunoBO. Subtende-se que a classe Aluno é a classe de negócio e acabo! Business Object é um design pattern que até hoje eu naum sei pq criaram ele!

Entendi o q vc quer dizer…
Mas eu to pensando em fazer uma classe CadastroServlet, uma AlunoBean, uma AlunoBO e uma AlunoDAO…

assim a classe q vc chamou de Aluno ficaria só pra armazenar os dados do aluno(AlunoBean).

o q vc acha?

O que eu acho, péssimo…

Criar uma classe AlunoBean e outra AlunoBO é uma coisa muito feia! :wink:

O exemplo que o pessoal passou é um espetáculo, onde Vc tem uma classe Aluno, AlunoDAO e o CadastraAlunoAction (Controle)!

Se vc quer não quer o método validate dentro da classe aluno (aluno.validate()), então cria uma classe só pra validação, tipo

ValidateUtil, NegociaValidateUtil, sei lá!

Uma outra possibilidade é vc fazer a validação dos dados do aluno no controle. Se o seu controle + view garantir que não entrará dados inválidos na camada de negócio, então vc pode optar por não usar a validação dentro da classe aluno!

J

Obrigado a todos pela ajuda…alguns conceitos estão muito mais claros agora…

Abraços

_

JDeveloper, o que estamos tentando te dizer é que não há necessidade de ter AlunoBean e AlunoBO :thumbup:

Pode nos dizer por que acha que é necessário? Ou é uma questão de gosto mesmo?

P

kina:

Assim deixando a minha classe “mais leve” pois não tenho métodos para serem persistidos?

Num DTO de verdade, utilizado para transmitir dados por uma rede e não para pegar dados do DAO e passar pro Joãozinho, você vai querer minimizar o tráfego, então é bom observar bastante os seus casos de uso e achar a melhor maneira de empacotar dados dos objetos de verdade em DTOs gordos que só servem para isso.

O padrão memento pode salvar vidas neste caso.

_

Como??

J

LIPE:
JDeveloper, o que estamos tentando te dizer é que não há necessidade de ter AlunoBean e AlunoBO :thumbup:

Pode nos dizer por que acha que é necessário? Ou é uma questão de gosto mesmo?

Eu acho q o código fica mais limpo se vc usar uma classe bean só pra armazenar dados do usuário e outra classe para realizar as regras de negócio.
No meu caso eu pretendo usar uma classe para armazenar os dados obtidos em várias telas. A cada tela que o usuário vai preenchendo eu vou adicionando os dados a essa classe.

Se eu armazenar os dados do usuário e as regras de negócio somente em uma classe essa classe vai ficar muito grande…o q eu acho ruim.

Entendeu?

P

LIPE:

Como??

Pegue seu objeto, extraia um memento. Junte todos os mementos dos objetos que precisar passar pela rede, empacote num grande DTO e mande pela rede.

Na outra ponta, injete (palavrinha na moda 8) ) o memento nos objetos do cliente, fazendo um update.

Na real é um jeito de evitar assemblers.

_

Shoes: mas para que juntar os mementos num DTO e não os próprios objetos?

Quantos atributos suas classes costumam ter a ponto de “ficar muito grande” colocar mais uma meia dúzia de métodos de negócio? @.@

P

LIPE:
Shoes: mas para que juntar os mementos num DTO e não os próprios objetos?

Um memento deve ser menor (em recursos, memória, blablabla) que um objeto inteiro, e ele tem o mínimo necessário apra recompôr o estado.

Quando você tem problemas numa rede a ponto de realmente precisar de DTOs, passar o mínimo possível de bytes pelo fio é essencial.

J

LIPE:

Quantos atributos suas classes costumam ter a ponto de “ficar muito grande” colocar mais uma meia dúzia de métodos de negócio? @.@

é uma classe de cadastro…então tem nome,idade,rg,cep,cpf,etc…
enfim…tem pelo menos 20 atributos…

20 atributos + 20 get + 20 set + os métodos de negócio…é bastante, não acha?

_

Shoes: entendi :smiley: realmente boa idéia.

jdeveloper: ah … getters e setters :expressionless: isso faz mal cara hehe

F

jdeveloper:
LIPE:

Quantos atributos suas classes costumam ter a ponto de “ficar muito grande” colocar mais uma meia dúzia de métodos de negócio? @.@

é uma classe de cadastro…então tem nome,idade,rg,cep,cpf,etc…
enfim…tem pelo menos 20 atributos…

20 atributos + 20 get + 20 set + os métodos de negócio…é bastante, não acha?

Nao. :stuck_out_tongue:

Faca a dica do Lipe. Pegue esse teu objeto e serialize ele em disco. Pegue uma lista com pequena quantidade desse objeto dentro e serialize em disco tb, pegue uma lista com grande qunatidade de objetos deste dentro e serialize tb. Verifique o tamanho e faca sua avaliacao.

É a melhor maneira para ter uma boa conclusao do que é grande ou nao para trafegar na rede.

]['s

_

fab, penso que ele se referiu ao tamanho do código.

[size=8]fab :XD:[/size]

J

LIPE:
fab, penso que ele se referiu ao tamanho do código.

[size=8]fab :XD:[/size]

é isso mesmo…o código fica muito grande…a manutenção fica mais difícil…

_

Para mim difícil é manter um relacionamento que só faz sentido para “o código não ficar muito grande” hehe

Na sua IDE não tem code-folding? Já tentou não usar getters e setters? :smiley:

J

LIPE:

Na sua IDE não tem code-folding? Já tentou não usar getters e setters? :D

não sei o q é code-folding :roll: atualmente eu to usando o netbeans 4.1

como é que eu vou preencher os meus atributos sem utilizar set? tiro o encapsulamento? melhor não,neh?

como é que eu vou pegar os dados para depois persistir sem usar get?

R

Discordo. O princípio de separação de responsabilidade alega que quem detém a informação é o responsável pela ação. Mas os DTOs não são detentores de informação nenhuma, é só um objeto repleto de atributos distintos.

Um Aluno englobar o que é inerente ao aluno não vejo como problema. Aliás, o que há de errado em se retornar um Aluno quando se solicita um Aluno?Ao menos para mim é estranho você retornar um objeto alienígena toda vez que solicitar uma entidade.

mvcsouza:

Além disso, o cara aí em cima lembro muito bem a facilidade em usar este padrão com os frameworks MVC que assumem este que DTO será o padrão usado na modelagem das classes de dados.

Qual framework em específico assume que você utilizará um DTO?

F

jdeveloper:
LIPE:
fab, penso que ele se referiu ao tamanho do código.

[size=8]fab :XD:[/size]

é isso mesmo…o código fica muito grande…a manutenção fica mais difícil…

Haaaa…nesse caso esquece os get e set burro sem necessidade. :mrgreen:

E falando nisso, fazer em duas classes nao ficaria maior nao? Alem de ter um outro .java enchendo o saco.

]['s

T

Olá!

jdeveloper:
é uma classe de cadastro…então tem nome,idade,rg,cep,cpf,etc…
enfim…tem pelo menos 20 atributos…

20 atributos + 20 get + 20 set + os métodos de negócio…é bastante, não acha?

1 - Talvez vc possa melhor seu modelo. Por exemplo, quando houver muita coisa, talvez vc possa quebrar esta classe em outras responsabilidades. Por exemplo, vc poderia criar uma classe Endereco. Na classe endereco vc coloca o endereco, cidade, bairro, rua, cep e etc…
Tente identificar em suas classes que é possível melhorá-las, e desacoplar dados em comum em uma outra classe!

2 - Não vejo problemas caso haja 20 atributos e 40 getters e setters em sua classe. Se vc não tiver como fugir dos getters e setters, e só vc se organizar. Por exemplo:

Se organize, que cria algumas convenções como por exemplo, deixe todos os seus métodos de negócio no final da classe! Assim, se vc tiver que trabalhar em algum método de negócio, vc sabe que a única coisa a fazer é se mover para o final do arquivo e encontrar o seu método de negócio!

Com os recursos das IDE´s que temos hoje, como o eclipse por exemplo, segure o control e clique com o mouse em cima do método que ele já te leva para a implementação do método!

Não há pq separar uma classe contendo só os métodos de negócio! :wink:

Abraços!
Thiago Senna

F

:?

J

fabgp2001:

E falando nisso, fazer em duas classes nao ficaria maior nao? Alem de ter um outro .java enchendo o saco.

]['s

Se for pensar assim (quanto menos classes melhor)…então faz tudo em uma classe só…os dados do aluno as regras de negocio e os metodos de persistencia… eu acho q fica muito feio! :wink:

P

Você pode me dizer como? Qual a responsabilidade do DTO e do tal BO?

A responsabilidade do DTO é pegar os dados do BO e passar para outro canto? Porque você não passa o BO?

Neste modelo você vai ter lógica de negócios altamente acoplada ao DTO, DTO altamente acoplado ao BO e View altamente ao DTO.

Lembre que dependência é transitiva, então tudo continua dependendo de tudo, e com mais o DTO no meio. Talvez assim seja melhor:

Como assim?

Para você faz mais sentido criar uma classe B que é uma cópia burra de outra classe A, e que no fim B vai ser usado para gerar um A?

Por que você não gera A em primeiro lugar? Qual o benefício do itnermediário?

mvcsouza:

Além disso, o cara aí em cima lembro muito bem a facilidade em usar este padrão com os frameworks MVC que assumem este que DTO será o padrão usado na modelagem das classes de dados.

Não existem (ou pelo menos não deveriam existir) “classes de dados” num modelo baseado em objetos.


P

Na verdade, me parece que o problema é um só: separação de responsabilidades. Pelo que você falou, seu entendimento de OOP o faria entupir o tipo com todos os métodos referentes a ele, na verdade você deveria separar as reponsabildiades entre outras classes.

Se você puder citar alguns casos problemáticos da tal classe, podemos trabalhar esse exemplo.

Bom, eu concordo em geral, mas não neste ponto. primeiro porque eu trabalho e trabalhei com projetos grandes e compelxos ao extremo, e os princípios de OOD foram formados baseados em projetos muito mais complexos do que eu ou a grande maioria dos frequentadores do GUJ pode sonhar em meter a mão.

M

Assim, DTO é lixo e só serve pra uma coisa, consertar uma falha dos EJBs, quem não usa EJB não deveria estar usando esse tipo de gambiarra.

T

Você consegue criar alunos capazes de se persistir e mantendo um código legível…

Como já rolou em outras discussões aqui no guj, Active Record é interessantíssimo, e além do mais, existem outras maneiras de seu objeto ser capaz de se persistir, desde que ele acesse uma interface que possui os métodos de persistência!

Ou seja, vc teria uma classes com seus métodos de persistência desacoplado da sua lógica de negócio, e sua classe de negócio é que diz quando ele deve ser persistido ou não!

P

Sim, falta a seta entre eles.

A pergutna é, para cada objeto de negócio você pode depender apenas do objeto em questão ou gerar uma dependência desnecessária utilizando um DTO. Para um exemplo com uma classe não aprece muito, mas isso vai crescer expotencialmente num sistema de verdade, e cada vez que você alterar uma coisa, vai alterar todo o ciclo de dependência.

O ponto é: em termos de acoplamento e dependência, DTO só piora.

Isso é programação procedural e existem ferramentas melhores para programar assim do que Java.

Vamos analisar o fluxo:
1 - Com DTO


2 - Sem DTO

Semrpe existe essa possiblidade, um bom projetista vais aber avaliar o custo/beneficio de toda flexibilidade.

Nesse caso especifico, você está falando de um cenário onde um DTO é um bom negócio. O que nós estamos discutindo é onde ele não é um bom negócio.

Acho que entendi seu ponto. O poblema é que você está colocando responsabilidades demais em Aluno.

Um aluno tem por responsabilidade executar suas regras de negócio (entrar em um curso, sair do curso, retornar seu boletim, sei lá…), o que você está falando é em misturar as responsabilidades de outras classes no aluno, por isso pedi um exemplo :wink:






_

Code-folding são aquelas setinhas que aparecem do lado do código para poder abrir/fechar o código. Assim ficam escondidas as linhas de código que não precisa ficar olhando o tempo todo. Acho que tem no Netbeans!

Sobre setters, é exatamente o contrário do que falou hehe quebrar o encapsulamento é chamar esses getters/setters de fora. Para preencher os atributos de seu objeto, use o construtor :smiley:

Sobre a ausência de getters/setters, leia meus favoritos! Isso foi amplamente discutido aqui no fórum, recomendo a leitura.

F

jdeveloper:
fabgp2001:

E falando nisso, fazer em duas classes nao ficaria maior nao? Alem de ter um outro .java enchendo o saco.

]['s

Se for pensar assim (quanto menos classes melhor)…então faz tudo em uma classe só…os dados do aluno as regras de negocio e os metodos de persistencia… eu acho q fica muito feio! :wink:

jdeveloper,

Mas estamos falando de duas classes que dizem respeito ao mesmo Objeto, no caso aluno. Nao da pra generalizar como tu fez.

]['s

_

mvcsouza entenda que não estamos falando que DTOs nunca devem ser usados. Só estamos dizendo que só devem ser usados em ambientes altamente distribuídos APÓS ter certeza absoluta que a carga de rede está exagerada.

E também não estamos falando para colocar todo o código dentro de Aluno. Mas é dividir as responsabilidades com coerência:

Ao inves de:

class Action {
    Aluno aluno = new Aluno();
    AludoDAO dao = new AlunoDAO();
    dao.save( aluno );
}

Fazer:

class Action {
    public void go() {
        Aluno aluno = new Aluno();
        aluno.save( aluno );
    }
}

class Aluno {
    public void save() {
        dao.save( this );
    }
}

Como deve bem saber por ter participado de projetos grandes, a primeira abordagem rapidamente se torna um inferno de manutenção com código repetido espalhado por todo o projeto.

T

Muito bém colocado! Com certeza, este é um fator que pode ser um diferencial em um projeto de grande porte!

Hoje estou fazendo refactoring em uma aplicação o o programador usou bastante buffer.write()., buffer.newLine() e buffer.flush(); sempre usando a mesma sequência! O texto que estava sendo passado dentro dos métodos Estava em inglês!

Dái, me abriram um bug para passar para Português! Pronto! Ferrou!
Essa rotina que usava 5 linhas se repete em média 12x distribuidamente em 17 queridas classes!

17 x 12 X 5 = 1020

Agora com meu refactoring, o q antes estava usando 5 linhas começara a uasr 2 linhas, entaum:

17 * 12 * 2 = 408

logo

1020 - 408 = 620

Nessa brincadeira estou eliminando 620 linhas de código desnecessárias.

Acho que este seria um exemplo simples para ilustrar como algumas rotinas repetitivas (mesmo que bém organizadas) podem ser simplificadas!

Fazer este refactoring nisso está super dispendioso, e vou com certeza levar mais de um dia para terminar!

mvcsouza, em minha opinião, acho que sempre que possível é melhor optar pela simplicidade! Apesar de vc gostar desta estrutura com TO, acredito que não usar o TO torne a aplicação mais simples, e até mesmo mais desafiador. :wink:

Abraços!
Thiago

P

Então o que voce está usando não é um DTO/VO/TO. Estes objetos existem apra transmitir dados, não para ser o estado de uma entidade.

No seu caso, então, meus diagramas estão errados, porque existe uma dependência de aluno para o DTO.

O que você está fazendo é simples:

AlunoDTO -> Estado
Aluno(BO)-> Comportamento

Ou seja: separando um objeto em duas classes.

Você programa em C? Se programa, vejamos:

aluno.h:

struct aluno {...}

aluno.c

void set_idade(int idade)
{
...
}

int get_media()
{
...
}

Qual a diferença?

Isto ao meu ver especializa o código e não espalha código como alguns 
colegas disseram. O desenvolvedor sabe com base no padrão onde está 
cada especialidade de código, seja validação, persistência e negócio. Além 
disso, a comunicaçào das mensagens entre as camadas se dá de forma 
muito mais otimizada, e de quebra eu não preciso alterar o meu código se 
algum dia precisar fazer uma chamada remota!

Otimizada por que?

Você cria uma classe a mais para cada classe de negocio hoje para evitar que num futuro que pode acotnecer ou não (o mais provável) você não precise criar uma classe para todas as operações remotas (que pode ser uma Session Façade, por exemplo)?

Me diz qual a vantagem de fazer isso e criar uma Façade Remota que retorna e recebe objetos “Aluno”.

E, novamente, qual exemplo você dá de uma classe que tenha tanta regra de negócio que fica impraticável utilizar OOP?

Um outro problema no codigo eh o servlet tocando a camada de persistencia diretamente, utilize uma camada de aplicação leve para isso.

P

Ola,

Existe uma diferença entre layer e tier. Utilizar DTOs para passar entre layers é besteira se stas ficam na mesma tier. Essa é a discussão. Se você ler o tópico, vai ver que todos aqui comentaram que DTO é sim válido para chamadas remotas. É um mal necessário.

Entretanto, pelo menos num ambiente normal, dificilmente você terá interfaces remotas que justifiquem um DTO. Mesmo onde você tem tais interfaces, é conveniente utilizar um profiler, verificar o tamanho dos objetos serializados, tráfego na rede e todas as outras variáveis para definir o DTO a ser utilizado, lembro que não rpecisa haver um mapeamento de 1 para 1 entre DTO e objeto, pelo contrário, é melhor você colcoar vários objetos num só DTO para economizar recursos.

Sou contra soluções tamanho-unico, mais ainda se envolve EJB. nos projetos em que trabalho varia sempre, e semrpe tentando eliminar ao máximo de EJB em função de tecnologias mais leves.

Pergunta simples:

Sabendo que o problema em trafegar dados em um sistema distribuído numa rede é basicamente o RPC e necessidade constante de trocar dados o tempo todo, o padrão DTO é utilizado para minimizar estas chamadas. Se seus DTOs são menores que um objeto de verdade, qual a vantagem em utilizá-los ao invés de apenas mandar o objeto?

Economizar alguns bytes na transmissão? Vale a pena aumentar a complexidade do seu projeto, criando uma classe só com estado, outra só com comprotamento, só para passar menos dados numa rede?

O real problema de transmissão em sistemas distribuídos não é o tamanho dos objetos individualmente, que geralmente é insignificante, mas sim a quantidade de vai-e-vem de dados o tempo todo e o tamanho do grafo de objetos que deve ser passado, que vaid epender basicamente do que o cliente vai fazer com os objetos.

No exemplo, se AlunoDTO tem uma referencia a um CursoDTO (ou curso BO, nao sei como vc prefere relaciona-los), e CursoDTO tem referencias a diversos outros AlunoDTO, que tem referencias a outros CursoDTo que por sua vez referenciam mais AlunoDTO… como seu DTO te ajuda a melhorar o desempenho?

A discussão já está descambando para a melhor estratégia em um DTO, mas o meu ponto é que não vale a pena complicar sua camada de negocios e criar classes que não obedecem os principios basicos de OOP para um requisito que:

1 - Não é onipresente (pelo contrário, é bem infrequente. Quantos aqui tem a camada de negocios em um servidor e a de web em outro na maioria dos projetos? Quantos viram isso uma ou duas vezes? Quantos nunca viram isso?)

2 - Pode existir, mas não ser necessário o uso de DTO (POJOs podem dar cotna do recado em muitos casos)

3 - Se realmente necessário, pode ser solucionado de uma forma melhor, usando Transfer Object Assemblers em cima de objetos de negócio.

Penso, mas não consigo entender porque você não consegue distribuir isso em objetos ao invés de usar registros.

A técnica se chama Programação em Camadas e Separaçãod e Responsabilidades, você poderia implementar uma Camada de Aplicação (Application Layer) utlizando, por exemplo um façade, ao invés de acessar o DAO de vez, atropelando a Camada de Negócios.

[]s

P

Bom, isso é fácil de testar :wink:

Como falei, fazendo o teste você vai comprovar que não importa passar 50kb a menos, o que importa é minimizar a comunicação, apra isso um DTO empacota tudo que o cliente vai rpecisar, esta é sua finalidade.

Como num mesmo nó você não tem dificuldade em comunicação (está tudo no mesmo espaço de endereçamento), você não vai precisar de um DTO.

Perdão, você está certo, eu não havia vista que começava outro arquivo no meio da tag [ code ], era isso que eu estava dizendo.

Dê uma lida em alguns textos sobre o assunto:


http://www.theserverside.com/news/thread.tss?thread_id=34278

mvcsouza:

A questão agora em minha mente é:

Até onde vai a inteligência da Entidade?? Aluno tem que saber fazer o que com ele mesmo? Quando eu passo para o BO??

O BO é o aluno. Isso resume OOP. Estado e comprotamento no mesmo construto.

Agora se você está pergutnando se o aluno tem que ter toda a lógica referente a ele, a respsota é simplesmente: não. Por que? Por que muitas relações em que o aluno participa são de responsabilidade de outros objetos, e devem ser distribuídas.

Imagina o seguinte:

Pelo que eu estou entendendo do seu ponto de vista (eu posso muito bem não ter entendido nada, ams é o que eu acho), o aluno deveria ter algo assim:

class Aluno{
 public void avisarAusenciaProfessor(Professor ausente){...}
}

Mas não, pdoe muito bem ser assim:

class Turma{
 List<Aluno> alunosInscritos= ...

 boolean vaiTerAulaHoje = true;

 public void avisarAusenciaProfessor(){
   vaiTerAulaHoje=false;
 }


 public boolean vaiTerAulaHoje(){ return vaiterAulaHoje;}

}



class Aluno{
 List<Turma> turmas = ...

 public void vaParaAAula(){
  turma turmaDeAgora = descobrirQualTurmatemAulaAgora();
  if(turmaDeAgora.vaiterAula()){
   assitirAulta(turmaDeAgora();
  }
  else{
   irAoCinema();
  }
 }
}

Isso foi um exemplo idiota, mas o princípio é este: separar responsabilidades.

P

Você não está rompendo a separação de camadas se não tocar uma camada que nãoe steja ligada, no caso do save(), não há problema.

Eu sabia que esse artigo ia causar coisas deste tipo :smiley:

Eu tenho essa revista e estou inclusive escrevendo um post no meu blog sobre isso. Fernando Lozano é sim um cara muito respeitado, mas o que ele afirma não tem fundamento na literatura.

Essa coisa de “antigamente se acahva tal, hoje em dia se acha isso” sem nenhuma referência, sem nenhum motivo (caso seja ele mesmo o autor da teoria), não me parece válido.

Tivemos uma discussão sobre um outro artigo dele aqui, eu o convidei para entrar mas parece que ele não teve tempo de participar.

Eu acho terrivelmente equivocada esta abrodagem e lamento que seja divulgada num veículo tão abrangente como a Java Magazine sem qualquer referência de onde se possa ter mais informação sobre essa teoria.

Segundo o que já li, o futuro da orientação a Objetos é ser Estruturada, com dados de um lado e lógica de outro. Isso não me parece sensato.

Até a próxima então :wink:

[]s

C

pCalcado,

Finalmente algum tipo de esclarecimento. Realmente eu estava confuso com este tópico, pois o artigo do Fernando Lozano foi um dos meus primeiros contatos com patterns…

Para mim sempre foi regra que: aluno.save() é ruim!

Agora é hora de considerar melhor a questao.

R

puxa, eu sei que não é legal colocar objetos totalmente burros em seu sistema, mas deixar os objetos super dotados não me parece muito bom…

P

O que voce chama de objetos super-dotados?

F

O que voce chama de objetos super-dotados?

Implicitamente: são objetos com muitos comportamentos.
O que nos leva a uma chamada recursiva nos topicos “programação procedural - objetos burros” , que só pode ser finalizada quando todos souberem que objetos são formados por comportamentos + dados.

Essas tópicos longos com opniões diferentes são o bicho. xD .

Nem sempre é preciso utilizar patterns. Mesmo quando utilizadas, suas patterns não precisam ser identicas ao do autor do livro ou artigo, é preciso saber ser flexivel e toma-las como uma base segura para a sua propria criação. Ou utilizar tim tim por tim tim se ela “te cair como uma luva”.

P

A grande dificuldade que eu vejo nas duvidas comoe sta eh uma soh: separar responsabilidades.

faq:

Nem sempre é preciso utilizar patterns. Mesmo quando utilizadas, suas patterns não precisam ser identicas ao do autor do livro ou artigo, é preciso saber ser flexivel e toma-las como uma base segura para a sua propria criação. Ou utilizar tim tim por tim tim se ela “te cair como uma luva”.

O mesmo com paradigmas (como OOP), a questao eh que ate agora, neste ou em tantos outros topicos, ainda nao vi um caso onde realmente fosse rpeciso adaptar os conceitos drasticamente.

F

Por isso são patterns.

M

carneiro:
Para mim sempre foi regra que: aluno.save() é ruim!

Dependendo de como você vai fazer, pode ser bom ou ruim. Eu, por exemplo, implementei o Active Record (o padrão que botaria o “save()” no aluno) com uma única interface (usando AOP) e sem adicionar uma linha de código nas classes do modelo (o Aluno, Turma, Disciplina, Produto ou seja lá o que for).

O que você tem que garantir é que a coisa seja maleável, que seja fácil de dar manutenção e de testar (não ficou tão fácil de testar quanto eu pensava, entretanto…).

P

Como ja mencionei algumas vezes aqui, ao inves de AR puro e simples, eu prefiro uma abordagem baseada em Observers.

Quando o objeto muda de estado (ou quando recebe um .svae(), mais pratico e usavel) ele avisa seus observadores, o DAO, Repositorio, whatever eh um destes.

T

IMHO, se seu objeto estiver super dotado é pq ele tem responsabilidade demais, e ele entaum poderia ser quebrado em mais classes de negócio. Assim, todos seus objetos se manteriam simples!

Mas pq ficou mais difícil de testar? Por causa do AOP? Ou por causa do ActiveRecord?

Quando eu testo, eu apenas passo um mock para minha classe de negócio, e no final do teste verifico se o método dao.save(aluno) foi realmente chamado e se recebeu o objeto correto por parâmetro.

UserStorie userStorie = null;
Mock mockPM = null;

public void setUp() {
	userStory = new UserStory("Saving a user story");
	userStory.setContent("XPTurbine must save user stories.");
	userStory.setEstimatePoints(2.5f);
	
	mockPM = new Mock(PersistenceManager.class);
}
	
public void testSaveUserStorie() {		
	mockPM.expectVoid("save", userStory);
	
	ReleaseManager manager = new ReleaseManager();
	manager.setPersistenceManager((PersistenceManager)mockPM.proxy());
		
	manager.saveUserStory(userStorie);	
}

public void tearDown() {
	mockPM.verify();
}

Entaum, baseado no exemplo acima, apesar de não ser exatamente um AR, acredito que testar um AR não deve ser muito diferente disso!

Estou errado?:smiley:

Abraços!
Thiago

C

Thiago, o singular de “user stories” eh “user story” :wink:

T

Valeu Carlos, vou arrumar os lugares onde cometi este pequeno deslize! :smiley:

M

Por causa da AOP, o meu código não fica nas classes do modelo como o seu. É difícil de explicar :lol:

Quando você mexer no AspectJ vai entender :mrgreen:

_

pcalcado:
Como ja mencionei algumas vezes aqui, ao inves de AR puro e simples, eu prefiro uma abordagem baseada em Observers.

Quando o objeto muda de estado (ou quando recebe um .svae(), mais pratico e usavel) ele avisa seus observadores, o DAO, Repositorio, whatever eh um destes.

Isso parece legal, mas quais as vantagens em cima de uma simples chamada ao DAO/Repository/WTFory?

P

LIPE:

Isso parece legal, mas quais as vantagens em cima de uma simples chamada ao DAO/Repository/WTFory?

Imagina seu Façade:

void createNewBugbear(){
  bugBear b = bugBearFactory.create();
  b.save();
}

Ou

void createNewBugbear(){
  bugBear b = bugBearFactory.create();
  bugBearDao.save(b);
}

Fora que assim você poderia passar seu objeto diretamente à camada cliente e ela salva-lo quando apropriado (ainda não pensei sobre isso direito).

_

Não expressei minha dúvida corretamente. Gosto sim de AR, o que te perguntei foi relacionado à aplicação de Observer :smiley:

P

Ah tah :stuck_out_tongue:

Você pdoe até não usar um observer:

class Bugbear{
  BugBearRepository home = null;

 public BugBear(BugBearRepository home){
   this.home=home;
 }

 public save(){
  home.save(this);
 }

}

Mas eu prefiro algo mais genérico:

//TODO: Extract Superclass

class Bugbear{
  List&lt;Observer&gt; myObservers = new ArraylList&lt;Observer&gt;();

 public void register(Observer o){
   myObservers.add(o);
 }

 public save(){
  for(Observer observer : myObservers)
    observer.notify(this);
 }

}

Não consigo imaginar um real bom motivo para observers quando você só tem um observer, mas não consigo gostar da primeira estratégia :frowning:

_

hehe foi esse lance de um Observer que pensei Shoes.

Disso aqui você não gosta?
class BugBear {
    private Repository home;

    public void installRepository( Repository home ) {
        this.home = home;
    }

    public void save() {
        home.save( this );
    }
}

Se sim, por quê?

P

É disso mesmo :P.

Os repositórios ficam entre os clientes (BugBearManager) e o domínio e referenciar uma camada superior de uma inferior é problema (e isso já deu uma bela discussão na lista de domaindrivendesign).

Se você colocar repositórios como observadores, elimina essa relação baixo-cima com uam abstração.

_

Aí na minha humildérrima opinião é perfumaria à toa. Além de gerar outro problema: como diferenciar os diferentes métodos a serem chamados no Repository sendo que com Observer tudo o que pode se fazer é um notify?

se protege do olhar assassino de Shoes

P

:evil: :evil: :evil:

Ok, mas se tiver algum outro observador, eu padronizaria isso

void notify(Object objeto)
if(objeto no sgbd)
 update(objeto);
else
 save(objeto);

Complexidade?

_

Isso é fácil quando utilizando o Hibernate.

E o delete()? E se o método create() deve retornar a chave primária? E no caso de load()?

P

LIPE:

E o delete()? E se o método create() deve retornar a chave primária? E no caso de load()?

O Repositorio continua existindo apra estas coisas :wink:

A coisa toda é evitar que todo método de uma interface XYZManager fique salvando o bojeto toda hora (se você rpecisa usar dois ou mais destes num caso de uso, se ferra).

_
Entendi, mas uma solução parcial não me parece suficiente:
// considerando que não precise retornar a pk
public void saveOrUpdate() {
    for(Observer observer : myObservers)
        observer.notify(this);
}

public void delete() {
    home.delete( this );
}

public void load() {
    home.load( this );
}

Mas com certeza há alguma maneira de abstrair isso. Não vale AOP XD

P

Uhmm…tem razão quanto ao delete.

Agora, query só pedindo rpo repositorio IMHO

_
Com certeza, senão fica uma zona. Criar um layer de abstração desse jeito seria besta:
class Repository {
    public void updateAccounts( BugBear bugBear ){ ... }
}

class UselessAbtractionLayer {
    public void updateAccounts( BugBear bugBear ) { 
        repository.updateAccounts( bugBear );
    }
}

class BugBear {
    public void updateAccounts() { 
        uselessAbtractionLayer.updateAccounts( this );
    }
}
R

Lipe,

ahmm… Eu apenas gostaria de registrar aqui minha insatisfação com o uso indiscriminado do DAO pattern.

public class ScrublesDAO {

      public void save(Pojo object) {
             hibernate = getSession();
             hibernate.save(object);
             closeSession();
      }

      public void delete(Pojo object){
             hibernate = getSession();
             hibernate.delete(object);
             closeSession();
     }
(...)
}

public class BubblesDAO {

      public void save(Pojo object) {
             hibernate = getSession();
             hibernate.save(object);
             closeSession();
      }

      public void delete(Pojo object){
             hibernate = getSession();
             hibernate.delete(object);
             closeSession();
     }
(...)
}

Não é que DAO seja uma idéia ruim, mas a interface Session do Hibernate já nem tem funcionalidade suficientes para a maioria das necessidades de um DAO. IMHO, se você puder evitar utilizar um DAO (e usar uma entidade mais genérica) melhor, você não acha ?

_

Para as operações CRUD dá para generalizar sim, ainda mais com Generics como o cv mostrou :smiley:

Mas não me lembro de criar um DAO/Repository/WTFory só com esses 4 métodos hehe

R

Acho que a maioria dos DAOs se resumem a isto. Acho que você poderia querer fazer buscas para alguns objetos chaves. Nesse caso, você poderia utilizar uma classe para realizar as operações de busca. Se isto ainda não for suficiente, ou as operações CRUD forem mais complexas do que as descritas aqui, então o padrão DAO pode ser (muito bem) considerado.

Agora, eu nunca utilizei o generics e sempre consegui generalizar o CRUD (no hibernate), porque o parâmetro desses métodos no session é Object.

_

http://www.guj.com.br/posts/list/15/20668.java

O

Estava passando por um dilema sobre DTO.
Estava pensando em usar DTO’s dinâmicos ou DTH (Data Tranfer HashMaps)
Vi que é bem utilizado pelo pessoal lá fora

http://helpdesk.princeton.edu/kb/display.plx?id=9772

http://www.theserverside.com/discussions/thread.tss?thread_id=9154

Gostaria da opinião de vocês.

A

só pra dar seqüencia nesse tópico (que está muito, muito maneiro)

eu não gosto de nenhuma das duas idéias.

Em um projeto recente vi que a abordagem do DTH seria legal mas fiquei com receio de complicar muito o código e acabei optando por usar CachedRowSet que, ao meu ver, reduziria esse risco (Floyd Marinescu sugere isso como um pattern mas eu nunca vi ninguém falando em CachedRowSet que não fosse a implementação da sun).

desculpem se falei alguma m ok?
acabei de chegar por aqui.

Também gostaria de trocar idéias sobre isso.

O

Ressucitando o tópico…
Por que os DTH complicariam o código ?

L

okara:
Ressucitando o tópico…
Por que os DTH complicariam o código ?

Porque você precisa de uma pensa de sets de uma lado e uma tonelada no outro?

Fora que DTH são um engodo, eles geram um tráfego enorme de dados e consomem memória a rodo.

M

louds:
okara:
Ressucitando o tópico…
Por que os DTH complicariam o código ?

Porque você precisa de uma pensa de sets de uma lado e uma tonelada no outro?

Fora que DTH são um engodo, eles geram um tráfego enorme de dados e consomem memória a rodo.


Depende.

DTH são uma boa maneira de abstrarir os Beans entre as camadas. E se o trabalho de gerenciar os HashMaps for bem feito (leia-se, o programador não precisa fazer nada) eu acho uma boa alternativa.

O

Tem como dar um exemplo disso ?

M

okara:
‘marcelomartins’:

DTH são uma boa maneira de abstrarir os Beans entre as camadas. E se o trabalho de gerenciar os HashMaps for bem feito (leia-se, o programador não precisa fazer nada) eu acho uma boa alternativa.

Tem como dar um exemplo disso ?


Não consegui pensar em nada simples para te exemplificar, então imagina no teu sistema web tu não quer que o JSP conheça tuas classes do dominio.

Então, antes de chegar no JSP uma classes de infraestrutura (framework) ve todos as classes que estão populadas e transforma para HashMaps. No JSP dá pra trabalhar como se fossem as classes no lugar dos HashMap, é transparente.

Não sei se fui bem claro, mas foi uma tentantiva. :wink:

O

Você transporta os objetos em forma de hashmaps ?
É isso ?
Mas que vantagem isso teria ?
Eu teria que distribuir os pojos (DTO’s) do mesmo jeito.
Então é melhor transportar pojos.

P

A vanategm é que você nãp criaria uma classe DTO por objeto, mas a pergunta seria:

Mas porque usar um DTO neste caso em primeiro lugar?

P

http://fragmental.com.br/wiki/index.php?title=Evitando_VOs_e_BOs

_

Excelente compilação, shoes. Obrigado :smiley:

R

Senhores,

Parabéns pelo excelente fórum e pela discussão em alto nível. 

  Gostaria de colocar algumas "gotas de pimenta" na conversa.

  Desenvolvemos aqui na empresa alguns sistemas usando CMP 2.0 e posteriormente começamos a utilizar o Hibernate como framework de persistência. Nos primeiros sistemas fizemos uso intensivo de DTOs e nos sistemas Hibernate passamos a utilizar os próprios Domain Beans.  pra contextualizar, as aplicações são divididas em camadas, onde os canais de interface com o usuários são desenvolvidas e implantadas em aplicações independentes das aplicações de negócio. Exemplo, aplicações clientes WEB e SWING, com as aplicações servidoras distribuídas através do uso de EJBs. 

  Alguns pontos sobre o uso dos Domain Beans como moeda de troca dos métodos com as aplicações clientes: 

 1. As aplicações se tornaram dependentes da solução de persistência. A biblioteca do Hibernate passou a ser necessária na implantação das aplicações clientes. Ou seja, se eu uso um TomCat para implementar minhas aplicações WEB preciso anexar o jar do Hibernate a um container que é somente WEB.

 2. Os Domain Bean Hibernate (pois eles passam a ser objetos Hibernate) quando enviados ao cliente são passíveis de lançarem exceções Hibernate. Por exemplo, um objeto A que possua uma coleção de objetos B ( tipo Funcionário com Dependentes) e cuja a associação está marcada com LAZY. Neste caso, se o programador da aplicação cliente tentar acessar a coleção de Dependentes recebe uma exceção Hibernate avisando que não é possível "carregar" os objetos pois estão fora do "contexto" do Hibernate.

Esses problemas sempre me remetem a questão do isolamento entre as camadas. Mesmo não trabalhando com sistemas distribuídos (SOAP, RMI, CORBA) a separação lógica entre as camadas do seu sistema devem continuar a existir e não me parece uma boa prática enviar objetos Hibernate ou EJB3 para uma página JSP. Como também o contrário, e muito mais fácil de ser percebido como uma prática ruim,  enviar para as camadas de négocio da aplicação,  objetos Struts (como os objetos que estendem o ActionForm) ou objetos que lidam com o protocolo HTTP como os HttpServletRequest.

Me parece bastante claro os objetivos de uma aplicação cliente: coletar e exibir dados. Nada mais. O fato de enviar um Bean “parrudo”, cheio de “regras de negócio” acredito que apenas dificulte o trabalho de quem implementa a aplicação cliente. Na grande maioria das vezes você precisa
contextualizar as suas regras de negócio ao escopo de uma transação, fora dela você está sujeito à inconsistências. A lógica de cada caso de uso faz parte da solução do sistema e deve ser descrita na aplicação servidora. Muitas das vezes apenas com os dados “inputados” pelo cliente o estado do objeto ainda se encontra “incompleto”, e que só vai ser “terminado” durante o decorrer da transação na aplicação servidora. Não adianta portanto que os “sets” ou os “validates” sejam executados pela aplicação cliente. É uma função dos componentes de sistema e dos componentes de domínio (vide UML Components - Cheesman).

Quanto a grande dificuldade de criar e manter DTOs, não vejo dessa forma. Exite uma classe (como a maioria das fornecidas pela Apache) que é a BeanUtils, que tem um método muito útil chamado copyProperties(). Com ele é possível facilmente popular os Domain Beans a partir dos Forms e/ou HashMaps e vice-versa. Quanto a gerar e regerar os Assemblers e os próprios DTOS, a maioria das IDEs já faz isso pra você.

Outra coisa, Beans simples normalmente são usados para telas de cadastro. Em grande parte dos casos de uso os objetos que chegam a aplicação cliente são mais complexos. Vide telas de consulta onde normalmente lidamos com “resultsets”, ou grafos de objetos.

Bom, acho que to escrevendo demais … STOP. :smiley:

Abração.

P

Oi, Renato,

Isso indica que você não está utilizando separação de Camadas. A Camada de Persistência é a única que deve (pode, na verdade) depender do Hibernate, se seu Tomat não é responsável pela persistência provavelmente você tem um problema de arquitetura.

Novamente vejo um problema de arqutietura aqui. Seus objetos persistidos pelo Hibernate deveriam ser POJOs, eles não podem depender do Hibernate. Essa dependência é um erro de projeto.

Este é um problema de Lazy-Loading, você tem opções para gerenciar este problema na Camada de Persistência ou simplesmente não utilizar este recurso.

Como falei antes este é o problema desta arqutietura: não existe separação de Camadas. Você está deixando lógica de persistência escorrer para a Camada de Negócios e isso não é culpa do framework :wink:

Exato e não há porque você fazer isso com Hibernate.

Para isso existem DTOs, que sao um conceito diferente de TO(antigo VO) ou até de objetos burros.

Não entendi o que isso tem a ver com TO/VO.

Hmm… Cheesman? Deixa eu adivinhar: CCE da PUC-Rio?

Uma biblioteca extra só para criar objetos burros? Acho que não condiz muito com OOP.

De qualquer forma o problema não é copiar dados apenas, é manter hierarquias paralelas artificiais de objetos.

Existem dezenas de maneira de lidar com isso num domínio rico, não vejo qual o problema.

R

Olá PCalcado,

A arquitetura de camadas que usamos é a seguinte: 

         
          VISÃO         _ 
            <=>           |
        CONTROLE      |   --- > WAR
            <=>           |
       DELEGAÇÃO   _|
            <=> 
         SISTEMA      _
            <=>           |  ----> EJB JAR
         DOMÍNIO     _ |   

 
  Para vc entender a dependência que o "Hibernate Domain Bean" gera nas aplicações clientes, experimente criar um WAR que receba um POJO que foi utilizado pelo Hibernate em um archive EJB como retorno de um determinado método de negócio, implementado por um Session Bean. Para o exemplo ficar legal, procure implantar as aplicações de forma independente, de preferência em application servers distintos, no melhor exemplo um TomCat e um JBoss. 

 Você vai perceber que para  "deployar" a sua aplicação Web no TomCat você vai ter que fornecer o jar do Hibernate.  Isso acontece  por que o POJO que representa uma entidade de negócio, que teoricamente é um objeto Java comum, é estendido pelo  Hibernate. Ou seja, o objeto que chega como retorno para você na tua camada de delegação não é mais um "Plain Java" mas um objeto Hibernate. Daí a tal da dependência. 

Quanto ao fato de criar estruturas paralelas, a primeira vista, realmente parece o fim do mundo. Concordo com você que "duplicar código" é sempre uma  idéia. Mas o fato de trabalhar por contratos e tentar isolar os clientes de componentes mais internos, eu considero crucial. O "Hibernate Domain Bean" acaba se tornando um "Mochileiro das Galáxias". Sai das camdas mais baixas do sistema (camada de persistência) e vai parar nas páginas JSP. Isso para mim é o que se chama de "ALTO ACOPLAMENTO". Ou seja, deixamos de ter trabalho criando estruturas paralelas mas ganhamos uma alta dependência dos clientes com pacotes e interfaces do tipo [i]br.com.acme.xpto.entidades.Aluno[/i]. Realmente não acredito que se justifique.

Abração.

C

Algumas perguntas:

  1. Camada de delegacao? Huh? :shock:

  2. Renatov:
    Para vc entender a dependência que o “Hibernate Domain Bean” gera nas aplicações clientes, experimente criar um WAR que receba um POJO que foi utilizado pelo Hibernate em um archive EJB como retorno de um determinado método de negócio, implementado por um Session Bean. Para o exemplo ficar legal, procure implantar as aplicações de forma independente, de preferência em application servers distintos, no melhor exemplo um TomCat e um JBoss.

Pra que? :?

Lembre-se da primeira grande regra de sistemas distribuidos: nao construa sistemas distribuidos :wink:

P

O sue problema é classloading: O classloader RMI não está disponível no seu contexto.

Como você resolve isso com EJBs se não colocar um jboss-client.jar da vida no classpath?

De qualquer modo este é o exemplo clássico do uso de DTOs: troca entre duas camadas físicas. Como falei o problema é arquitetrual.

Não senhor. Objetos de infra-estrutura gerados automaticamente como os do Hibernate não podem ser considerados mochileiros porque são transparentes apra o desenvolvedor/projetista.

Por seu argumento AOP é algo que provoca acoplamento e aumenta a dependência, já que se baseia em substituir classes por stubs e proxies.

Recomendada a leitura do Patterns of Enterprise Application Architecture.

F

Regras de Négocio utilizam o padrão composto e aconselho que fiquem em uma classe separada.

Por exemplo: Se você tiver que implementar mais regras de négocio para cliente diferentes?

Classes de objetos do dominio, ou conceito do mundo real chamadas de Classe Conceitual.

Mas temos objetos chamados de Classe de Software - Classe que representa uma perspectiva de especificação ou implementação de um elemento de software, independente do processo ou método. Utilize o padrão Invensão Pura, sem obrigatoriamente utilizar um posfixo DTO, VO ect.

Uma classe anêmica só é anêmica se forçada.
Martin Fowler não expandiu tanto seu conceito assim.

F

“Mochileiro das Galáxias” KKK

F

@pcalcado, o que o Renatov (espero não ter me enganado) está tentando dizer é que (se entendi bem): Se uma entidade possui uma collection o Hibernate “injeta” um objeto que possui caracteristicas bem diferente de uma collection da api Java e que pertence a api do Hibernate, se algum método que manipule essa collection for acionado em um local onde a infra do hibernate não estiver presente ocorre a exception. Isso geralmente ocorre em sistemas onde o modelo está sob o “dominio” de um web server e o cliente é um swing por exemplo.

@todos, no livro pojo in action (indicado tambem pelo pcalcado, aliás obrigado por essa dica) o autor comenta sobre esse dilema.

flws

M

Cara, falando sério…

Não acho que o uso de DTOs deva ser condenado em ambientes não-distribuídos. É uma forma muito elegante de resolver o problema e usa o principio de separação de responsabilidades favorecendo o desacoplamento do código. Um problema que eu vejo em deixar o DTO de lado e criar uma classe que englobe tudo como no caso citado acima (Aluno), é o seguinte. Quando o DAO vai buscar alunos por classe por exemplo, você vai criar uma coleçào de alunos (classe Aluno com dados e métodos de negócio) e retornar para o view. Fica meio sem quê nem pra quê.
Além disso, o cara aí em cima lembro muito bem a facilidade em usar este padrão com os frameworks MVC que assumem este que DTO será o padrão usado na modelagem das classes de dados.

M

Cara, realmente são opiniões muito distintas…

Mas cheguei nesta conclusão após enfrentar um projeto imenso para secretaria de fazenda envolvendo um Contribuinte, Impostos, Declarações… Você já pensou no que seria um contribuinte com todas as suas regras de negócio e todos os seus atributos (sim, não há como negar que contribuinte possui atributos) em uma única classe, apenas para fazer com que Contribuinte seja responsável por tudo inerente ao contribuinte?! Concordo que seria lindo, que é o princípio de OO e tudo mais… mas é inviável. Teríamos uma classe com mais de 15000 linhas fora a persistência. Pense em um obterContribuintePorFiltro() em um DAO. Você já pensou na marreta que é instanciar uma classe de contribuinte com todos os seus métodos de negócio e persistência (entendo que se o contribuinte é responsável por tudo relacionado ao contribuinte, seus métodos não devem se limitar apenas a validação) e retornar uma coleção destes para exibir numa grid?
Prefiro saber que um contribuinte é um Contribuinte e que este contém as informações do meu contribuinte. Quem vai validar e estabelecer regras de negócio relacionadas a algum procedimento feito com um contribuinte é o objeto de negócio apropriado. Quem vai persistir é o DAO apropriado. Na view eu recupero e seto as informações do contribuinte e passo o contribuinte para quem sabe o que fazer com o contribuinte!

Mas é questão de opinião e experiência… Projeto grande faz a gente mudar a visão às vezes.

Discordo. O princípio de separação de responsabilidade alega que quem detém a informação é o responsável pela ação. Mas os DTOs não são detentores de informação nenhuma, é só um objeto repleto de atributos distintos.

Um Aluno englobar o que é inerente ao aluno não vejo como problema. Aliás, o que há de errado em se retornar um Aluno quando se solicita um Aluno?Ao menos para mim é estranho você retornar um objeto alienígena toda vez que solicitar uma entidade.

mvcsouza:

Além disso, o cara aí em cima lembro muito bem a facilidade em usar este padrão com os frameworks MVC que assumem este que DTO será o padrão usado na modelagem das classes de dados.

Qual framework em específico assume que você utilizará um DTO?

M

pcalcado,

Compreendo, mas no seu modelo “Sem DTO” o que chega para o Servlet? Não há dependência entre MostraAluno e Aluno? Acho que é uma dependência entra as três camadas da mesma forma… Prefiro trabalhar com aluno sendo apenas os dados do aluno. Quem tem que saber fazer os precessos em cima do aluno são as classes reponsáveis pelos processos. Veja que não discordo do seu ponto de vista com relação ao purismo OO. Mas não consigo concordar em manter uma estrutura pesada como um aluno quando tudo o que eu preciso na view são apenas os dados do aluno… E se existe uma possibilidade do seu projeto crescer e você separar o container web do de aplicações para distribuir? Deixa o peso da aplicação só la no container e nas classes de negócio… Acho que devemos expor o que é estritamente necessário para a camada. A view só precisa dos dados e passa a bola pra frente.
Por outro lado, se é para deixar tudo encapsulado em um Aluno, que este delegue para as classe especializadas como DAOs e BOs… Acho que não podemos querer puristas sempre, se fosse assim, o Aluno tinha que se persistir!!! Para que DAO?

Eu considero que há muito pano na manga para discussão…

M

Thiago Senna:

, desde que ele acesse uma interface que possui os métodos de persistência!

Ou seja, vc teria uma classes com seus métodos de persistência desacoplado da sua lógica de negócio, e sua classe de negócio é que diz quando ele deve ser persistido ou não!

Concordo, mas a interface que possui os métodos de persistência seria implementada por uma classe especializada, correto? E não o próprio Aluno como no caso em questão.

Essa é a discussão: até que ponto deve-se embutir funcionalidade numa classe que representa o Aluno e a partir de quando deve-se delegar para classes especializadas? Eu sou a favor do TO puro… Classes especializadas cuidariam do resto, mesmo com o efeito colateral da dependência do TO entre as camadas, que na minha opinião é perfeitamente aceitável e administrável. Alguma coisa tem que ser passada entra as camadas(View, Controller, Model), senão nào há comunicação entre elas…

M

caro pcalcado,

Temos uma percepçào um pouco diferente do que seria o DTO, ou de como usá-lo. No diagrama que você mostrou, com relação às sequencias do modelo com DTO, não há a necessidade de se persistir o estado no objeto Aluno, conforme você ilustrou. Isto já foi feito no DTO e esta é justamente a sua função, manter estado. Se o DTO mantém estado, não há necessidade de se criar um objeto Aluno e restaurar o estado a partir de um AlunoDTO, nem o contrário.

Veja um exemplo de como seria um pseudo fluxo em código:

/***********  Na Servlet ****************
AlunoDTO aluno = new AlunoDTO()
// persiste estado no DTO a partir dos parametros do request
aluno.setEstado( *** a partir dos parameters **** );  

GerenciadorAluno.incluir(aluno);




/**************************************
class GerenciadorAluno {
   
  public void incluir(AlunoDTO aluno) {
       // Valida o aluno e inclui via DAO ou se a inclusão for complexa e
       // envolver processos de negógio delega para o AlunoBO que se
       // encarrega de tratar as regras
       // AlunoBO.incluir(aluno);
        AlunoDAO.incluir(aluno);
  }
}

Esta é a seqüência. Portanto, perceba que não há necessidade de injetar o estado do aluno em um objeto Aluno a partir de um AlunoDTO. O alunoDTO em si é o estado. Penso que o objeto Aluno sugerido por você existiria como um BO, no caso da necessidade de validações especiais e realizações de regras de negócio durante determinada operação sobre o aluno.


Isto ao meu ver especializa o código e não espalha código como alguns colegas disseram. O desenvolvedor sabe com base no padrão onde está cada especialidade de código, seja validação, persistência e negócio. Além disso, a comunicaçào das mensagens entre as camadas se dá de forma muito mais otimizada, e de quebra eu não preciso alterar o meu código se algum dia precisar fazer uma chamada remota!

Abraços,

M

Nào entendi muito bem esta questão. Pelo que percebi, você atribui ao fato de se criar um Session Façade a solução das chamadas remotas? O que quis dizer foi que meus objetos DTO usados hoje apenas para manutenção de estado na aplicação seriam a forma mais adequada para transferência numa chamada remota, ou seja, não precisaria me preocupar com estruturas mais otimizadas para tranasferência de minhas entidades. As entidades já são esta estrutura.

Não sei se você usa esta prática em aplicações distribuídas com seus projetos, mas aqui é comum a criação de um session façade para cada módulo do sistema. Por exemplo, um façade para um módulo de Mátricula, um Façade para o módulo de cobrança, um façade para o módulo de Controle de Notas… Como a aplicação já trabalha desta forma (recebendo e devolvendo entidades DTOs) bastaria adicionar a camada EJB sem alterar muito as assinaturas. Claro que atentando para o padrão Session Façade (seu conceito).

Pense numa declaração de imposto que envolva dependentes, valores, bens, dados do contribuinte, rendas… E a quantidade gigantesca de regras associadas a cada variação em cada um de seus atributos no momento de sua criação?

Realmente, não entendi… No código do exemplo, o Servlet chama o gerenciador. Por favor, exemplifique o caso com um exemplo citando o nome da técnica ou padrão que deveria ser usado.

Valeu,

T+,

M

Com relação às suas perguntas direcionadas a performance de rede… Não sei, mas penso que a transferência de objetos burros será inquestionavelmente menos custosa em qualquer situação do que um objeto de mesma entidade com inteligência… Mas o fato do objeto conter listas e mais listas de referências a outros objetos seria um problema em qualquer situação numa tentativa de minimizar os custo de transferência. Este caso normalmente seria feito via gambiarra como você conhece o DTO!

Com relação ao último item, o código de exemplo já não está fazendo isso, na medida em que ele faz uma chamada ao Gerenciador ao invés de chamar diretamente o DAO?

Com relação a ser ou não burrice ou horrível passar Objetos burros na mesma layer… Realmente não considero. Acho que é uma forma padronizada e unificada de se representar a entidade… A questão agora em minha mente é:

Até onde vai a inteligência da Entidade?? Aluno tem que saber fazer o que com ele mesmo? Quando eu passo para o BO??

M

pcalcado,

Isso para mim é uma dura discussão… Seu exemplo na minha opinião expressa exatamente sua opinião que, como já te falei, não a considero de forma nenhuma incorreta. Só acho que ainda há uma etapada a ser vencida no seu código.

Uma coisa me surgiu na cabeça: Você falou sobre a separação entre a view e a aplicação usando uma camada leve e tal… Como o Gerenciador do Exemplo. Só que veja bem: Se eu recupero um aluno na view e restauro um estado qualquer neste Aluno, eu posso muito bem, na view, executar o Aluno.save() que, ao meu ver, seria um rompimento desta camada… Posso estar errado…

Vou colocar alguns trechos sobre este assunto que foi publicado por Fernando Lozano na java magazine (não sei qual sua opinião a respeito desta revista muito menos sobre o autor), mas vale como mais uma opinião:

"Talvez sua dúvida surja de um erro comum na modelagem orientada a objetos - o de modelar classes de informação, por exemplo “Cliente”, agregando a elas funcionalidades de negócios. Mas é necessario modelar os próprios processos de negócios, em geral decorrentes dos casos de uso do sistema. As classes que realizam tais processos não têm estado persistente (pois representam atividades sendo realizadas), e são elas que contêm a inteligência de negócios do sistema. Para modelar esses processos adequadamente, em vez de diagramas de classes, procure concentrar-se nos diagramas de atividades (para modelar o processo em si) e os de sequencia/colaboração (permitindo identificar como as classes trabalham juntas para realizar o processo no sistema) (…)

A classe ClienteDTO não deve ser responsável pela sua inclusão, atualização, etc. Nem, digamos, por validar o seu prórpio crédito ou classificar a si mesma como um “cliente vip”. Como o conceito de cliente é independente de tecnologias e produtos, por exemplo, de banco de dados, ele deve ser modelado numa classe separada e pode ser utilizado por vários processos de negócios diferentes. Por isso deve estar disponível de forma leve, sem sem criar dependências artificiais entre tais processos. (…)

Coloque agora o cliente em algum contexto, por exemplo, a venda de eletrodomésticos. Aqui o cliente poderia ser utilizado no processo de vendas, junto com dados do produto, nota fiscal, pagamento, condições de entrega, etc. Uma classe de negócios reúne todas as informações necessárias (os dtos correspondentes) e efetiva a operação, provavelmente chamando em sua implementação métodos dos DAOs relacionados e/ou outras classes de negócios.

Pense bem: não faz sentido, conceitualmente, inserir inteligência relativa à realização de uma venda em nenhuma classe de informaçào envolvidas. Será que a classe Nota Fiscal deveria saber como autorizar um pagamento por Cartão de Crédito? Deveria “PagamentoEmCartao” saber que existe uma promoçãoem que a própria loja está financiando o parcelamento sem juros do home theater sem repassar nada ao cliente? Estes dois exemplos ilustram possiveis violações de encapsulamento das classes envolvidas, mas o fato é que alguma classe precisa ter esta inteligência. "

Recomendo realmente a leitura deste artigo. Trata-se de um cara experiente que ilustra o texto com vários exemplos reais.

[]`s

Marco Vinicius

Agradeço a você por proporcionar uma discussão de muito bom nível com uma base forte de conhecimento. Isso nos ajuda a ampliar nossa capacidade de visualização dos problemas e como enfrentá-los de forma inteligente.

Caso tenha interesse na revista, procure adquirí-la no próprio site: Edição 20 - Ano III.

Criado 9 de agosto de 2005
Ultima resposta 11 de ago. de 2005
Respostas 113
Participantes 22