Repository

Objetivo

Centralizar e mediar operações de persistência de objetos de domínio.

Propósito

O padrão Repository (Repositório) for introduzido por Martin Fowler como uma forma de separar as responsabilidades de domínio das responsabilidades de persistência.

Em seguida, Eric Evans, usou o mesmo conceito no contexto de Domain Driven Design (DDD), onde o Repository (Repositório) é um padrão útil para isolar a persistência do domínio.

O propósito do Repository é permitir que os objetos de domínio, como Serviços (padrão Service) ou Validadores ((padrão Validator), possam inquirir sobre instâncias das Entidades do domínio. Para isso o Repository disponibiliza métodos que permitem obter as respostas e esse inquéritos.

O domínio não lida com o detalhe de como os dados são persistidos ou como os encontrar, essa responsabilidade é do Repository. Também não é permitido que as classes de domínio - chamadas de Entidades - possam depender de detalhes de persistência. Todos os detalhes são abstraídos pelo Repository.

O repositório é normalmente definido como uma interface, ou classe abstrat, na camada de Dominio cuja implementação é realizada na camada de persistência. A implementação do Repositório interage com a camada de mapeamento de dados e traduz os dados entre os modelos de persistência e de domínio.

Implementação

Existem várias formas de implementar o padrão Repository, contudo todas passam pela definição de uma interface onde as classes do Domínio são usadas como parametro e retorno. Não ha detalhes relacionados à persistencia nessa interface.

A implementação da interface de um Repository se resume a cumprir o contrado com base em alguma outra API de persistencia. A implementação do Repository terá acesso a objetos do dominio e acesso ao objetos da camada de persistência como sejam objetos no padrão Domain Store ou no padrão DAO. A implementação é então responsável pelo mapeamento da entidades para os objetos de persistencia, e de volta. Esta responsabilidade pode ser delegada a objetos Data Mapper e nesse caso a implementação de Repository se torna apenas uma orquestradora da interação entre os Data Mapper, os objetos de domínio e a camada de persistência e os seus respetivos objetos de dados.

É possível implementar um Repository utilizando tecnologias de mais baixo nível como JBDC por exemplo, mas não é recomentado. É mais simples se o Repository apenas estabelecer as pesquisas (queries) e não ter que controlar como elas são executadas.

Note
É importante notar que um Repository não tem que ser implementando com persistência em bancos de dados, pode ser uma persistência em arquivo, na memória, ou outro meio, contudo nas aplicações corporativas o Repository comunica, na vasta maioria dos casos, com uma camada relacionada a bancos de dados.

O papel do Repositório é comandar a camada inferior a obter os dados já persistidos e depois converter esses dados para os objetos do modelo de domínio. Quando o objeto de domínio é persistido, o Repositório realiza o caminho inverso coletando os dados persistentes dos objetos de domínio e repassando-os para a camada de dados.

Repositórios do Spring não são Repositórios, são DAOs

O framework Spring ficou muito famoso e é muito utilizados em projetos, inclusive sobrepassando o uso de JEE. O Spring é popular e conhecido por facilitar a vida do programador. No Spring o programador pode construir uma interface e marcá-la com a anotação @Repository e isto faz com que o Spring - com mais algumas configurações e seguindo algumas convenções - gere automaticamente o código necessário para cada método nessa interface.

Isto leva os desenvolvedores a acreditar que desta maneira estão implementado a interface de um Repositório tal como entendido no DDD, mas na realidade é a automação da implementação de um DAO. Isto porque os objetos envolvidos nesta interface são objetos de persistência que têm que ser mapeados - via Spring - para a sua contra-parte no banco de dados (tabela, documento, etc…​).

Este equívoco de confundir os objetos mapeados com o banco de dados como sendo as entidades do domínio também está presente em outras tecnologias como JPA e Hibernate.

Implementando Repository com DAO

Uma opção para implementação do Repositório é utilizar objetos Data Access Object (DAO). O DAO não trabalha com os objetos de Entidade, mas com objetos de persistência, normalmente, mas não limitado a, objetos que mapeiam tabelas em bancos de dados.

A implementação do repositório deve então mapear as operações do dominio para operações no DAO e mapear os objetos usados entre os modelos de Entidade e de Tabela.

Implementando Repository com Domain Store

Outra opção, mais recente, é utilizar o padrão Domain Store. Neste modelo existe apenas uma API central para manipular a persistência de todas as Entidades. Para isso o Domain Store mapeia as entidades para as tabelas necessárias e consegue realizar operações de leitura e escrita automaticamente.

Um Domain Store se propõe a persistir as entidades do domínio diretamente, mas dependendo de como o mapeamento é feito entre a entidade e a persistência, pode ser introduzido um acoplamento - usualmente na forma de anotações - entre o domínio e a persistência que não é uma boa prática, pois verdadeiras classes de entidade são isoladas e independentes da tecnologia de persistência. Permitir e manter este isolamento é o papel do Repository, então ao anotar as classes de domínio com anotação de persistência matamos o papel do Repository.

Domain Store é uma nomencltura infeliz, ja que frequentemente as classes utilizadas são na realidade as classes de dados da camada de persistência e não classes do domínio. Isto é comum em JPA/Hibernate e LINQ.

Data Mappers

Fazer a conversão entre objetos de persistência e objetos de domínio pode ser uma tarefa um pouco repetitiva e pode acontecer que mais do que um repositório utiliza os dados de uma mesma tabela o que significa replicar o código de mapeamento. É aqui que objetos de mapeamento de dados podem ajudar.

O objetos Data Mapper servem exclusivamente para mapear entre os objetos de dados e os objetos de domínio de uma forma organizada que não implica replicar código e permite manter o código DRY.

Chaves de Domínio

A tendência natural é permitir que objetos de domínio tenham campos com os valores dos ids de banco. Isto é muito útil, mas viola a independência de camadas criando um acoplamento. Por outro lado, nem sempre o id do banco é um bom identificador de domínio.

A ideia de ter objetos no padrão Tiny Type que modelem as chaves de domínio e que possam conter qualquer informação chave - inclusive as chaves de persistência, mas não apenas elas - ajuda a manter o isolamento e o desacoplamento entre a camada de domínio e a de persistência.

Discussão

O padrão Repository é um dos padrões mais utilizados, pelo menos em teoria, mas, na prática, é muitas vezes confundido com o padrão DAO.

O padrão Repository deve ser utilizado no escopo de DDD (Domain Driven Design) para manter o isolamento entre a camada de domínio e a camada de persistência. Se a sua arquitetura não utiliza conceitos de DDD, não utilize o padrão Repository.

Padrões relacionados

O padrão Repository se relaciona ao padrão Service porque estruturalmente se trata de uma interface com várias implementações. Contudo, este é um serviço cuja responsabilidade exclusiva é fornecer uma metáfora de persistência e localização dos dados (query).

Vimos também que o Repository se relaciona aos padrões DAO e Domain Store já eles são usados na implementação de um Repository. Normalmente um dos dois é usado, mas é possível usar os dois na mesma implementação.

Também se relaciona ao padrão Data Mapper para o qual delega o mapeamento entre os objetos de persistência e os de domínio.

Indiretamente, se relaciona ao padrão Tiny Type usado para adicionar semântica aos objetos usados nos métodos do Repository que de outra forma seriam String ou long sem significado semântico. O padrão Tiny Type é especialmente útil para encapsular chaves, sejam de persistência ou de negócio.

Bibliografia

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

[3] Eric Evans, Eric J. Evans Domain-driven Design: Tackling Complexity in the Heart of Software: Addison-Wesley Professional (2004)

Scroll to Top