[quote=sergiotaborda]Exato. Repare como a herança não está de acordo com o que vc mesmo disse.
- O repositorio é único para cada entidade. Se existem várias implementações possiveis, então não é único. Logo, o repositorio não pode ser uma interface. Tem que ser um objeto concreto ( não abstrato, não interface, não estático)
- O repositorio comunica com um ou mais DAO. Primeiro, herança não é comunicar. Comunicar significa uma relação de cooperação (de composição). Segundo, se o DAO for a implementação de repositorio então não tem como chamar mais do que um DAO.
Acho que isto já basta para mostrar que o Repositorio é um objeto distinto do DAO. Quando digo distintio quero dizer que um não RepositoryPessoaherda ou implementa o outro. A relação é Reposiotorio—>(1…*) DAO e não Repositorio—|> DAO nem DAO—|>Repositorio[/quote]
Bem, agora que você deu essa aula sobre Repository e DAO deixa eu monstrar um pequeno exemplo (agora mais real):
Entidade Pessoa:
[code]public class Produto {
private int id;
private String nome;
private int quantidade;
public Produto(int id, String nome, int quantidade) {
this.id = id;
this.nome = nome;
this.quantidade = quantidade;
}
public int getId() {
return this.id;
}
public String getNome() {
return this.nome;
}
public boolean checaQuantidade() {
if(this.quantidade > 2) {
return true;
}else{
return false;
}
}
}[/code]
Classe “de ação” Inventario
[code]public class Inventario {
private List produtos = new ArrayList();
public void adiciona(Produto produto) {
if(produto.checaQuantidade()) {
System.out.println("Produto adicionado. (" + produto.getNome() + ")");
this.produtos.add(produto);
}
}
public boolean salva() {
if(!(this.produtos.isEmpty())) {
RepositoryInventarioImpl repo = new RepositoryInventarioImpl();
repo.salvar(this.produtos);
return true;
}else{
return false;
}
}
}[/code]
RepositoryInventarioImpl:
[code]public class RepositoryInventarioImpl implements RepositoryInventario {
public boolean salvar(List vetorProdutos) {
RepositoryProdutoImpl repopdr = new RepositoryProdutoImpl();
try {
boolean pdrstatus = repopdr.salvar(vetorProdutos);
return pdrstatus;
}catch(Exception e) {
// lança exception
}
return false;
}
}[/code]
RepositoryProdutoImpl:
[code]public class RepositoryProdutoImpl {
public boolean salvar(List vetorProdutos) {
Iterator iterator = vetorProdutos.iterator();
JDBCProdutoDao dao = new JDBCProdutoDao();
try {
while(iterator.hasNext()) {
Produto pdr = (Produto) iterator.next();
dao.salvar(pdr); // manda a interação pro DAO...
}
}catch(Exception e) {
// lança a exception (joga para frente)
}
return true;
}
}[/code]
e a app teste…
[code] public static void main(String[] args) {
Produto pdr1 = new Produto(1, “Livro OOP”, 1);
Produto pdr2 = new Produto(2, “Livro Design Patterns”, 3);
Produto pdr3 = new Produto(3, “Abobora”, 4);
Produto pdr4 = new Produto(4, “Pringles :)”, 5);
Inventario estoque = new Inventario();
estoque.adiciona(pdr1);
estoque.adiciona(pdr2);
estoque.adiciona(pdr3);
estoque.adiciona(pdr4);
if(estoque.salva()) {
System.out.println("Produtos Persistidos no database suavemente");
}else{
System.out.println("'Faiou' a persistência...");
}
}[/code]
Bom. O que acontece é o seguinte:
- Crio alguns objetos Produtos
- “Inicializo” o Inventario
- Adiciono os produtos 1 a 1 no Inventario
- Chamo o estoque.salva() que irá persistir as informações no Inventario.
Agora vem o principal:
5. No Inventario#salva é chamado o RepositoryInventarioImpl#salvar() que recebe um List com os produtos do Inventario.
6. Esse Repository por sua vez, “delega” a ação de adicionar os produtos para outro Repository (como você sugeriu (explico abaixo o por quê fiz)), o RepositoryProdutoImpl.
7. RepositoryProdutoImpl, recebe esse List e como é tarefa dele, prepara os dados para serem repassados a DAO’s necessária - neste caso somente 1 DAO, a JDBCProdutoDao.
8. JDBCProdutoDao se comunica com o database via jdbc e retorna um bool que é transmitido até chegar no Inventario#salvar(), ou, em caso de exceptions, dispara a Exception e essa se propagará até a Inventario#salvar() também.
Legal, agora os motivos disto (na minha opinião e entendimento à sua explicação):
RepositoryInventarioImpl existe, pois talvez eu possa ter alguma rotina de persistência na parte de inventário, logo, eu faço uma façade da RepositoryProdutoImpl para “juntar as rotinas”. Façade simples, onde não impede a comunicação direta com o RepositoryProdutoImpl. (como pede o próprio pattern).
Isso quer dizer que caso eu venha a ter a necessidade de persistir alguma outra informação relacionada à entidade Produtos - como o usuário que fez a alteração no estoque, criando uma espécie de log - durante um ação de salvar(), eu poderia muito bem deixar a cargo do meu RepositoryInventarioImpl receber as novas entidades (via parametros no comportamento) e cuidar de persisti-las para mim, correto ?
Certo. Nada de mau teria caso eu repassasse o objeto Pessoa para a DAO, pois até onde sei, é na DAO que eu crio o Statement, e passo os valores usando bindParam, por exemplo.
Jóia. DAO retorna o renomado ResultSet para o Repositório responsável, o qual se vira para criar os objetos de retorno.
Então o Repository basicamente garante que o objeto seja “traduzido” para o idioma do banco de dados/XML/TXT, e ao mesmo tempo, “traduz” tabelas e linhas em objetos que o sistema entende. Ele é nosso tradutor, nosso modem (analogia ruim, mas vale).
[quote=sergiotaborda]Mas tome atenção que o codigo salva() em pessoa não é necessário para o Repositorio.
Esse codigo em pessoa é o uso de um outro padrão (ActiveRecord).[/quote]
Verdade. No ActiveRecord a implementação da persistência é feita diretamente na entidade. Já com o Repository aplicado, ele é quem cuida disto.
huum! O Registry é o cara que “evita” que eu fique fazendo instâncias de Repositórios em todos comportamentos de persistência, como eu fiz no exemplo acima:
[code]public boolean salva() {
if(!(this.produtos.isEmpty())) {
RepositoryInventarioImpl repo = new RepositoryInventarioImpl();
repo.salvar(this.produtos);
return true;
}else{
return false;
}
}[/code]
Ele me auxilia no “encapsulamento” dessas instâncias… seria meio que uma fábrica (factory) então ?
[quote=sergiotaborda]É que com active record qualquer objeto pode mandar salvar a pessoa, mesmo quando não deveria.
O salvar é uma ação protegida por validações e outros processos do sistema que não cabem dentro do objeto pessoa ou do método salvar. [/quote]
Certo. No caso, o Inventario é uma classe que apenas possui comportamentos de persistência, logo, neste caso em especifico, não há problema em trabalharmos com o salvar() nele, correto ?
Falando nisto, veja:
public void adiciona(Produto produto) {
if(produto.checaQuantidade()) {
System.out.println("Produto adicionado. (" + produto.getNome() + ")");
this.produtos.add(produto);
}
}
Antes de jogar no List mais um objeto Produto, o Inventario comunica-se com o objeto Produto que foi passado a ele para ter certeza de uma regra em espeficico. Caso, negativo nada é feito, do contrário, o produto entra na lista do Inventario.
A pergunta é: validações de regra de negócio é preferível ficar sempre no modelo, correto ? Pois uma possível implementação seria validar no RepositoryProdutoImpl, mas eu mesmo não achei muitos motivos para isto…
Certo. Repare que no exemplo, eu mando um List de Produtos ao repositório para serem persistidos. Repare também que é o Repository quem faz a interação item a item e adiciona usando a DAO em jogo. Logo, no meu exemplo, eu não conseguiria “pular” o Repositório (algo como: Inventario -> ProdutoDAO), pois estou dependendo da interação. Por isto, estaria meu repositório executando tarefas que não é obrigação dele ? Ou seja, essa interação deveria ficar lá no Inventario#salvar(), ou o Repositório pode colocar a mão-na-massa também ?
Realmente você explicou de forma excelente ! Sem dúvidas foi bem útil para mim !
Abraços e muito obrigado ! (y)