Olá Pessoal, tudo bom?
Essa semana vamos falar um pouco sobre o pattern DTO ou Data Transfer Object. Veja na continuação.
O que é DTO?
Um objeto provedor de dados de várias classes que transita entre camadas de negócio. Esse objeto aglutinador é constituído dessa forma a fim de reduzir o número de chamadas de métodos entre várias classes.
Exemplificando 1 – Removendo informações indesejadas
Imagine que temos em nosso projeto uma classe Endereco conforme a Figura 01.
Repare que essa classe possui um id, que é a forma de armazenarmos essa informação dentro do banco de dados. Agora estamos criando um serviço rest, que retorna informações através de uma URL na internet. Se utilizarmos diretamente essa classe Endereco, iremos expor para quem utilizar o serviço rest o id dessa classe. Assim podemos criar uma classe EnderecoDTO que será utilizada por esse serviço, mas sem exibir o id para o mundo, como mostra a Figura 02.
A classe EnderecoDTO possui o seguinte código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
package br.com.mauda.dto; public class EnderecoDTO { private String rua; private Integer numero; private String complemento; private String bairro; private String cidade; private String estado; private String pais; public EnderecoDTO(){ } public EnderecoDTO(Endereco endereco){ this.rua = endereco.getRua(); this.numero = endereco.getNumero(); this.complemento = endereco.getComplemento(); this.bairro = endereco.getBairro(); this.cidade = endereco.getCidade(); this.estado = endereco.getEstado(); this.pais = endereco.getPais(); } public String getRua() { return this.rua; } public void setRua(String rua) { this.rua = rua; } public Integer getNumero() { return this.numero; } public void setNumero(Integer numero) { this.numero = numero; } public String getComplemento() { return this.complemento; } public void setComplemento(String complemento) { this.complemento = complemento; } public String getBairro() { return this.bairro; } public void setBairro(String bairro) { this.bairro = bairro; } public String getCidade() { return this.cidade; } public void setCidade(String cidade) { this.cidade = cidade; } public String getEstado() { return this.estado; } public void setEstado(String estado) { this.estado = estado; } public String getPais() { return this.pais; } public void setPais(String pais) { this.pais = pais; } } |
Repare que a classe EnderecoDTO possui um construtor que recebe uma instância de Endereco e preenche (popula) os atributos internos do DTO através da chamada de métodos get() da instância de Endereco, além de reutilizar código, pois evitar o seguinte código em N lugares do seu projeto:
1 2 3 4 5 6 7 8 |
EnderecoDTO enderecoDTO = new EnderecoDTO(); enderecoDTO.setRua(endereco.getRua()); enderecoDTO.setNumero(endereco.getNumero()); enderecoDTO.setComplemento(endereco.getComplemento()); enderecoDTO.setBairro(endereco.getBairro()); enderecoDTO.setCidade(endereco.getCidade()); enderecoDTO.setEstado(endereco.getEstado()); enderecoDTO.setPais(endereco.getPais()); |
Exemplificando 2 – Aglutinando informações de várias classes
Suponha que em nosso projeto temos duas classes Album e Artista, conforme Figura 03. Album possui um atributo String titulo e Artista possui um atributo String nome. Além disso, existe uma associação 1 para muitos entre eles.
Toda vez que precisamos exibir as informações do nome de um artista a partir do seu Album temos que utilizar o seguinte código:
1 |
album.getArtista().getNome() |
Assim, toda vez temos que acessar o método getArtista() para conseguir seu nome. A classe AlbumDTO vem para remover essa necessidade da chamada a mais do método getArtista(), conforme mostra a Figura 04.
A classe AlbumDTO possui o seguinte código:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
package br.com.mauda.dto; public class AlbumDTO { private String nomeArtista; private String titulo; public AlbumDTO(Album album){ this.titulo = album.getTitulo(); this.nomeArtista = album.getArtista().getNome(); } public String getTitulo() { return this.nomeArtista; } public void setTitulo(String titulo) { this.titulo = titulo; } public Integer getNomeArtista() { return this.numero; } public void setNomeArtista(String nomeArtista) { this.nomeArtista = nomeArtista; } } |
Da mesma forma temos o construtor que recebe uma instância de Album e trabalha a fim de preencher (popular) os atributos internos do DTO. Aqui nesse caso haverá apenas 1 vez a chamada ao método getArtista(), visto que depois será acessado o método getNomeArtista(), o qual irá retornar diretamente a informação do nome do Artista.
finally{
Assim terminamos a descrição sobre o pattern DTO.
Duvidas ou sugestões? Deixe seu feedback! Isso ajuda a saber a sua opinião sobre os artigos e melhorá-los para o futuro! Isso é muito importante!
Até um próximo post!
Miquéias Fernandes says
Li em vários lugares, mas somente aqui foi explicado de forma simples e direta sem jargões em excesso, Obrigado e parabéns pelo trabalho!
Mauda says
Olá Miquéias, tudo bom?
Obrigado pelo feedback! Isso significa muito pra mim!
Precisando estamos por aqui!
Obrigado!
Antonia Luciana says
Faço das palavras do Miquéias as minhas, muito obrigada! Gostaria de tirar dúvidas, posso? Sou iniciante no mundo java e venho buscando entender esse padrão. O que devo entender quando você diz “…e popula os atributos internos do DTO” ou ” a fim de popular os atributos internos do DTO”? Essa palavrinha ficou como pulga atrás de orelha.
Além disso, queria confirmar: quando eu for utilizar o put, delete, post e tal, posso então usar apenas o EnderecoDTO?
Mauda says
Olá Antonia, tudo bom?
Obrigado pelo feedback! Isso significa muito pra mim!
“…e popula os atributos internos do DTO” – Popular vem de preencher, assim ele preenche os atributos internos do DTO, ou seja, busca as informações que estão no parâmetro passado e preenche os atributos do DTO.
Quando você está trabalhando com serviços rest é interessante aplicar um tipo especifico para cada tipo de requisição. Por exemplo, quero fazer uma requisição de delete. Normalmente é passado apenas o id que eu quero deletar. Assim na própria url do serviço rest eu já faço isso, exemplo /carro/{id}, onde esse id é o que eu quero deletar. Então você aplica o DTO para determinadas requisições, como post e put, que vão inserir e atualizar um objeto, ou um filtro para uma requisição de get, onde esse filtro pode ser um DTO completamente diferente com somente os atributos da minha pesquisa, filtro da tela, por exemplo.
No caso o EnderecoDTO seria utilizado para o post e put. Talvez no get se o filtro de pesquisa fosse igual aos atributos.
Duvidas a mais só perguntar.
Precisando estamos por aqui!
Obrigado!
jr domingos says
Mauda !!!! você é um enviado de Deus !!! Aqui no grupo você é um Herói ! kkk
Mauda says
Olá Domingos, tudo bom?
Obrigado pelo feedback!
Só por curiosidade, qual grupo?
Precisando estamos por aqui!
Elias da Silva Rita says
Bom dia.
O que você acha sobre colocar Herança em DTOs? seria uma má prática.
Por exemplo, tenho um DTO de Pessoa que possui alguns dados e tenho um DTO de PessoaFisica e outro de PessoaJuridica. Seria correto colocar o física e jurídica herdando do pessoa.
OBS: Sei perfeitamente que DTOs não podem ter comportamento de regra de negócio, mas podem ter comportamento de preenchimento de dados, assim como você colocou o DTO AlbumDTO recebendo Album no construtor e lá pega os dados.
Esse pergunda osbre herança de DTOs é porque caso eu não colocar, a minha classe de serviço que irá consumir esses DTOs poderia ter código duplicado. Como ficaria nesse caso?
Mauda says
Olá Elias, tudo bom?
Eu não considero uma boa prática. Objetos DTOs são classes simples, talvez com alguma associação com outro DTO.
Mas vou repetir campos? Sim. É feio? Pra mim não.
Não é porque você está repetindo atributos que você está com o código feio. Se você estivesse repetindo lógica de métodos entre outros pontos aí sim eu consideraria o código feio.
A minha visão atual do DTO é que ele é utilizado em retornos de serviços rest. Dessa forma, é mais fácil você fazer um serviço que traga as informações bem pontuais, fáceis para um cliente, seja um angular, react ou ainda um outro BackEnd q utilize o retorno. Então quanto mais simples, mais fácil para o cliente utilizar. E na minha opinião ainda é que a interface deve ser o mais “burra” possível, somente processando coisas muito pontuais. Deixa o processamento mais pesado para o BE, normalmente vai ter um poder de processamento maior que a máquina do usuário do seu sistema.
Duvidas mande mais questões!
Obrigado pelo feedback!
Precisando estamos por aqui!
Luciano Mendel says
Excelente post direto e objetivo.
Mauda says
Olá Luciano, tudo bom?
Obrigado pelo feedback!
Precisando estamos por aqui!
Obrigado!
Hugo says
Showww… Parabéns. Entendi tudo
Mauda says
Olá Hugo, tudo bom?
Obrigado pelo feedback!
Precisando estamos por aqui!
Obrigado!
Matheus Henrique Rodrigues Barbosa says
Parabéns! Texto conciso, explicativo e com muita qualidade!
Mauda says
Olá Matheus, tudo bom?
Obrigado pelo feedback!
Precisando estamos por aqui!
Obrigado!