Data Mapper

Objetivo

Encapsula a conversão entre objetos do modelo de persistência e do modelo de domínio

Propósito

O propósito de um objeto DataMapper é encapsulaer a lógica necessária para produzir ou preencher um objeto do modelo de domínio com base num objeto do modelo de persistência. Pode também oferecer a operação contrária produzindo, ou preenchendo, um objeto do modelo de persistência com base num objeto do modelo de dominio.

É muito comum ter que traduzir o modelo de persistência para o modelo de dominio, e vice-versa. O DataMapper encapsua esta lógica de uma forma que pode ser utilizada multiplas vezes.

Implementação

A implementação de um DataMapper é com um método para cada atividade.

class ProductDataMapper {

   Product fromTable(ProductTable table){...}
   ProductTable toTable(Product table){...}
}

Normalmente o DataMapper é usado com um Repository e é deixado para o repositório a criação dos objetos. O mapper recebe o objeto já criado e simplesmente preenche os dados:

class ProductDataMapper {

   Product fromTable(ProductTable table, Product product){...}
   ProductTable toTable(Product product, ProductTable table){...}
}

É ainda possível criar uma interface genérica:

interface DataMapper<M, T> {

   M fromTable(T table, M product);
   T toTable(M product, T table);
}

e aplicá-la quando necessário:

class ProductDataMapper implements DataMapper<Product, ProductTable>{

   Product fromTable(ProductTable table, Product product){...}
   ProductTable toTable(Product product, ProductTable table){...}
}

Discussão

O conceito e implementação de um DataMapper é muito simples e próximo ao de um conversor. Contudo, conversões de dominio pode ser mais complexas e é possivel que um DataMapper necessite usar os serviços de um, ou mais, objetos DataMapper. A composição de *DataMapper normalmente acompanha a composição de entidades no modelo de dominio.

Em certos cenários e tecnologias o DataMapper é substituido por um simples conversor. A principio isto funciona, mas em casos particulares um conversor não é suficiente. O exemplo clássico é o mapeamento de objetos de enumeração (enums). Estes são objetos que - no código - referenciam várias opções para um valor e no banco correspondem a algum tipo de código - normalmente inteiros ou letras. O mapeamento de um enum para um inteiro corresponde a uma especificação de como o modelo de persistencia do banco corresponde com o modelo de objetos na linguagem, e um conversor pode não ser suficiente para atenter este mapeamento.

Um exemplo de um DataMapper de enum que contém mais informação que os objetos sendo mapeados

class ProductTypeDataMapper extends EnumDataMapper<ProductType, Integer>{

   ProductTypeDataMapper(){
      map(ProductType.SERVICE, 1);
      map(ProductType.GOOD, 2);
   }
}

Os objetos de DataMapper, ao contrário de conversores, poder conter informação que nenhuma dos objetos convertidos tem. No caso do exemplo, nem o número 2 tem informação que está relacionado a ProductType.GOOD , nem ProductType.GOOD tem informaão do numero 2

Padrões relacionados

O padrão DataMapper se relaciona ao padrão Repository onde é usado para auxiliar a conversão de dados. Pode também ser usado em conjução ao padrão DAO mas o mapeamento seria entre objetos do modelo de persistência e objetos da API de comunicação com o banco de dados.

Bibliografia

[1] Martin Fowler Patterns of Enterprise Application Architecture: Addison-Wesley Professional (2003)

Scroll to Top