Factory para persistir classe adequadas ou existe outra partner para isso

Bom antes que alguem fale, sim ja pesquisei arduarmente sobre o assunto que irei introduzir, e o mais incrivel: ou existem topicos mto infantis com pessoas que nao sabem nada(desculpe nao estou querendo ser presuncioso) ou acham q sabem … ou assuntos avançandos que geralmente se disvirtuam.
vamos ao interessa.
por favor o exemplo que irei colocar é infantil porem, na maioria dos casos sempre ta errado. deem uma olhada no forum ou no google e vcs veram.

ipessoa
nome
sobrenome
TemFilhos

iEmpresa
razaosocial
TemFilial

Classe Pessoa implenta iPessoa
Nome
TemFilhos

iCliente
nome
DescontoDoCliente

ClientePessoa extents Pessoa e implementa iCliente
ClienteEmpresa extents Empresa e implementa iCliente

ja criei ClienteEmpresa e ClientePessoa pois o calculo de seus desconto sao diferentes, e logo adinte teram mais variações. Logo se a unica diferença fosse cpf e cnpj nao teria pq criar duas classes, porem na maioria dos exemplos a razao de ser ter duas classes para clientes é unica e exclusivamente cpf e cnpj q nao faz sentido nehum.

para mim nao me estender mto a questao é a seguinte

Classe OpVenda … essa classe tem um cliente que ira comprar alguma coisa, para essa classe oq importa é que quem vai comprar seja um cliente. Logo terei OpVenda.DefineCliente(iCliente cliente). e terei um OpVenda.DefineCliente.cliente_ID.

DefineCliente(iCliente cliente)
this.cliente = cliente
cliente_ID = cliente.ID

estarei passando como parametro no preenchimento da venda um ClientePessoa por exmplo.

Agora como faço quanto quero pesistir OpVenda?
como terei
apenas cliente_ID e uma variavel apontando para um interface iCliente
como irei carregar(pesistir) cliente se eu nao sei mais se ele é ClientePessoa ou CLienteEmpresa? e nao posso persistir uma interface
logo achei essa alternativa:

OpVenda.Carrear
iCliente this.cliente = new FactoryCliente.carregaCliente(thies.cliente_ID); //esse metodo retorna uma interface iCliente
//sendo que cliente_id ja esta persistido

FactoryCliente.carregaCliente(int cliente_ID) : iCliente
ClienteEmpresa ce = new ClienteEmpresa
if ce.carregar(cliente_ID) then
return := ce
else
ClientePessoa cp = new ClienteEmpresa
if cp.carregar(cliente_ID) then
return := cp

nao estou usando hibernate pois apenas quero endender se isso faz sentido.

Agradeço desde ja. desculpe pelos erros portugues, e desculpe a má implemntacao da sintaxe em java.

Olá, achei seu modelo bastante complicado. Da uma ollhada nele.
So uma sugestão.

class Pessoa {}
class Venda{
List<Produto> produtos;
ClientePessoaFisica
ClienteEmpresa
}

Não entendi bem o seu modelo, da uma olhada quando fica meio confuso e que pode ficar melhor.

Bons Códigos.

Factory (Fábrica) é um padrão para criação de objetos. As fábricas constroem coisas.
Construir um objeto é fazer “new” dele. A fábrica mais simples é a que simplesmente faz new e retorna.
O que vc quer é um mecanismo que procure um objeto através de uma condição , no caso o valor do ID, e retorne o objeto dentro dessa condição.

Podemos imaginar , abstratamente, que todos os objetos de uma certa classe ficam numa lista na memoria.
Procurar por um deles significaria iterar esta lista e comparar os atributos dos objetos até que a condição de procura fosse satisfeita. O padrão que conrresponde a isto é o padrão Repository.

O ID é uma variável privada do sistema de persistencia. Se não existice banco de dados , vc não precisava dessa ID. ID é portanto uma chave para o sistema de persistencia de forma que o registro seja identificado de forma independente dos valores que ele contém. O que eu estou dizendo com isto é que vc não deve manipular o ID nem passar o ID de forma explicita. Se isso for necessário encapsule o ID num objeto.

A sua interface iCliente não tem um campo ID. Isso é correto. Mas o objeto ClientePessoa tem um ID. Porquê ? Porque ClientePessoa é um objeto persistivel.

Então vc pode fazer assim

interface Persistable 
getID() : Object 
setID(Object obj);

class ClientePessoas extends Pessoa implements Cliente , Persistable


class ClienteRepository {
  static Cliente findByID(Object id ){
    // código de procura

  }
}

Vc pode tirar o i de iCliente , em Java os nomes das interfaces não começam com I.
A longo prazo isso so serve para atrapalhar. Chama Cliente mesmo.

O OPVenda tem como parametro um Cliente. Eu não tendi muito bem o que seira OpVenda.DefineCliente(Cliente c)
parece uma método estático. Se for, tudo bem, mas chame algo mais perto da realidade OpVenda.vendePara(Cliente c)
Concerteza terá mais parametos como o produto e a quantidade ou vc seta isso depois com um addItem(Produto, quantidade)

Então se vc quer vender parao Cliente com id 345 ficaria assim


Cliente cliente = ClienteRepository.findByID(345); // procura o cliente
OpVenda venda = OpVenda.vendePara(cliente); // cria a venda
VendasRepositroy.store(venda); // persiste a venda

Repare que não precisa saber de 345 é uma pessoa ou empresa
o método findBy é que tem que descobrir isso e devolver o objeto certo.

[quote=sergiotaborda]Factory (Fábrica) é um padrão para criação de objetos. As fábricas constroem coisas.
Construir um objeto é fazer “new” dele. A fábrica mais simples é a que simplesmente faz new e retorna.
O que vc quer é um mecanismo que procure um objeto através de uma condição , no caso o valor do ID, e retorne o objeto dentro dessa condição.

Podemos imaginar , abstratamente, que todos os objetos de uma certa classe ficam numa lista na memoria.
Procurar por um deles significaria iterar esta lista e comparar os atributos dos objetos até que a condição de procura fosse satisfeita. O padrão que conrresponde a isto é o padrão Repository.

O ID é uma variável privada do sistema de persistencia. Se não existice banco de dados , vc não precisava dessa ID. ID é portanto uma chave para o sistema de persistencia de forma que o registro seja identificado de forma independente dos valores que ele contém. O que eu estou dizendo com isto é que vc não deve manipular o ID nem passar o ID de forma explicita. Se isso for necessário encapsule o ID num objeto.

A sua interface iCliente não tem um campo ID. Isso é correto. Mas o objeto ClientePessoa tem um ID. Porquê ? Porque ClientePessoa é um objeto persistivel.

Então vc pode fazer assim

interface Persistable 
getID() : Object 
setID(Object obj);

class ClientePessoas extends Pessoa implements Cliente , Persistable


class ClienteRepository {
  static Cliente findByID(Object id ){
    // código de procura

  }
}

Vc pode tirar o i de iCliente , em Java os nomes das interfaces não começam com I.
A longo prazo isso so serve para atrapalhar. Chama Cliente mesmo.

O OPVenda tem como parametro um Cliente. Eu não tendi muito bem o que seira OpVenda.DefineCliente(Cliente c)
parece uma método estático. Se for, tudo bem, mas chame algo mais perto da realidade OpVenda.vendePara(Cliente c)
Concerteza terá mais parametos como o produto e a quantidade ou vc seta isso depois com um addItem(Produto, quantidade)

Então se vc quer vender parao Cliente com id 345 ficaria assim


Cliente cliente = ClienteRepository.findByID(345); // procura o cliente
OpVenda venda = OpVenda.vendePara(cliente); // cria a venda
VendasRepositroy.store(venda); // persiste a venda

Repare que não precisa saber de 345 é uma pessoa ou empresa
o método findBy é que tem que descobrir isso e devolver o objeto certo.[/quote]

Boa sérgio, mandou bem … utilizando repository e tudo mais, não tem nem o que acrescentar :slight_smile:

Antes d td Obrigado Sergio pelas observações. É interessante citar que sou programar delphi, porem estou migrando algumas aplicações para java, e aproveitando para aplicar um poo descente e com bons beneficios.
bom … mais um comentario: se vc esta iniciando no mundo poo aproveitem esse otimo forum e as pessoas que participam dele. estou esperando a mais de 3 semanas uma resposta em um forum delphi e outro c#, ou respondem bobagens ou nao respondem nada.
A outra dica: peguem uma aplicaçao que ja esta funcionando e pronta e tentem migrar para uma programação oo. assim fica mais facil de entender os beneficios do poo, pois a regras e fluxos do negocio ja estao em sua cabeça.

bom vamos lá
Sergio vou abusar da sua boa vontade, ou daqueles que queiram contribuir para um assunto bem mascado porem ainda nao digerido por mtos.

quanto sua obs sobre o Persistable, valeu, mas como com certeza absoluta vou sempre usar um bd, vou manter o ID em classes que teram seus obetos persistidos.

class ClientePessoas extendsPessoa implementsCliente
quanto a isso entao esta tranquilo, fica a interface Cliente e a classe Pessoas

para Vendedor
class VendedorPessoas extendsPessoa implementsFuncionario

oq interessa para mim é seu findByID do repository

classClienteRepository {
staticCliente findByID(Object id ){
// código de procura

}
}

esse codigo de procura vai procurar primeiro em uma um obj da classe ClientePessoa se nao achar vai procurar em um obj da classe ClienteEmpresa? exemplo: ClientePessoaRepository.findByID depois ClienteEmpresaRepository.findByID isso dentro do repo do ClienteRepository.findBy
Pergunto isso pq Obj do tipo Cliente(interface) nao podem ser persistidos, e tb nao tenho um mapeamento com meu hibernate(por exemplo) de Cliente.
Cliente conceituamente nao existe, existe somente um ClientePessoa. sendo assim tenho mapeado ClientePessoa e Clienteempresa e esses sim eu posso usar resursos do meu framework de persistencia para buscar um ou outro atraves do ID.

quando eu digo que nao tenho um Cliente, é pq nao posso cadastrar ou conceber um Cliente(interface). eu sempre terei um ClientePessoa ou um ClienteEmpresa. estou dizendo isso pq ja vi implementações que tem a Classe Cliente, depois a classe ClientePF e ClientePJ que herdam de Cliente (“Classico isso”), porem se acredita que isso sao 3 modelos, 3 regras, e nao, pois qual a diferença de Cliente para ClientePF dentro do negocio.

no meu caso aqui quero apenas usar o recurso da interface Cliente para implementar no futuro ClienteEmpresaRevenda.

Se nao fui bem claro desculpa
Valeu gente

Desculpe, Joaquimnabuco, mas eu não tinha visto esta resposta.
Passo a comentar.

Não. Não é assim que funciona. Embora Cliente não seja algo concreto , existem realmente clientes no seu modelo.O que o seu modelo trata é de clientes , são eles que fazem compras. Não interessa se são pessoas ou empresas. O repositório deve apenas trabalhar com clientes e retornar apenas clientes. Vc escolheu usar uma interface para cliente, mas no seu caso uma classe abstrata seria melhor. Isto porque vc não vai criar uma classe que é simultanemente um Cliente e um não-cliente como ClienteFornecedor. O ponto, é que cliente é uma entidade abstracta do seu modelo. Ela é realmente mais importante que ClientePessoa ou ClienteEmpresa.

Os modelos de banco para isto são vários, mas em todos eles existe algum atributo da entidade abstrata que
identifica que tipo de subclasse está em causa. O caso mais simples é colocar todos os dados do cliente pessoa e do cliente empresa numa mesma tabela. Alguns campos vão ser comuns, como nome, por exemplo. Um campo q tb vai ser comum é o campo identiifcador de subclasse. Imagine-se que 1 é pessoa e 2 é empresa.
Então quando eu pesquisar o banco dentro do repositorio eu farei algo como “select * from Cliente where cliente_id = 357”, isto vai retornar todos os campos, entre os quais o campo que indeitifica a subclasse.
Ai eu faço o seguinte:


class ClienteRepository {   
  static Cliente findByID(Object id ){   

 // tou usando o JDBC para ser mais explicito
// repare que todos os objetos que saem daqui são Persistable.

     ResultSet rs = /// executa a query que filtra pelo ID, isto vai trazer 1 ou zero resultados
  if (    rs.next()){
     final int descriminador = rs.getInt("cliente_descriminador");
     if (descriminador ==1){
         // é um cliente pessoa 
         ClientePessoa pessoa = new ClientePessoa(id);
          // preenche os campos com os dados do resultset 
         
         return pessoa; // posso fazer isto porque pessoa é um cliente
     } else {
         // é um cliente empresa
         ClienteEmpresa empresa= new ClienteEmpresa (id);
          // preenche os campos com os dados do resultset 
         
         return empresa; // posso fazer isto porque empresa é um cliente

      }
     
} else {
   throw new Exception("Cliente não encontrado")
}
  }   

  static void store (Cliente cliente){
   //grava o cliente no banco

   // o problema é identificar o ID do cliente sem que cliente tenha a interface Persistable.
   // bom, o cliente não tem Persistable, mas todos os clientes reais têm. 
// Logo, eu posso sempre fazer isto:

   Persistable p = (Persistable)cliente;

// porque eu garanto no método acima que ClienteEmpresa e ClientePessoas são Persistable
    
// depois é só ler os campos e jogar num insert ou update
 }
}  

Não. Cliente existe sim. É abstrato, mas existe. (se não existisse não haveria uma interface para o representar)

Não necessariamente. Se Cliente é uma classe abstrata vc nunca vai poder criar objecos que são apenas clientes sem serem pessoas ou empresas, mas poderá trabalhar com todos estes de forma unificada já que todos são clientes.

Po Sergio vc é rápido. Qualquer coisa me manda a conta pela a ajuda. Valeu mesmo.

Bom finalmente acho q vou resolver essas duvidas, pq nem com o prof da faculdade consegui resolver, por increvel que pareça. Bom comentários a parte vamos la:

Acho que talvez minha modelagem não esteja adequada. Será que não seria mais sensato eu fazer assim segundo oq vc comentou:

Interface Cliente
String Nome;
Double MeuDesconto …

Abstract class AbstractCliente implements Cliente

class ClientePessoa extends AbstractCliente implements Pessoa, Persistable

Sinceramente nunca vi uma modelagem coerente de clientes pessoa e empresas, acho q tem mta confusao por ai, embora pareça simples.

Eu estava usando uma interface Cliente anteriormente pois queria aproveitar a classe Pessoa e classe Empresa via herança(esse é um dos poucos lugares que usa herança pois sei os ricos disso). Como mais adiante teria o papel do vendedor eu tb usaria essa herança de pessoa, so que ao invés de implementar Cliente eu iria implementar Funcionario: class Vendedor extends Pessoa implements Funcionario, Persistable
Isso poupa o tempo de ter q fazer todos membros de pessoa e empresa, como os famigerados cpf e cnpj, que na verdade tem um porem, se a pessoa for americana ela nao vai ter isso, ou se a empresa for alemã tb não vai ter cnpj, mas o pior é ter que fazer a parte de endereço e telefone.

Voltando ao caso de Cliente:
no futuro vou ter ClienteEmpresaRevenda, ClienteFinal e outros mais, por isso achei o uso da interface Cliente mais adequada ao invés de usar uma classe abstrata implementando a propria Interface Cliente. Contudo se em um momento louco eu quiser vender para um cachorro, ou querer ter um cachorro como Cliente poderei class ClienteCachorro extends Cachorro implements Cliente , Persistable. e assim o metodo VenderPara(Cliente cliente) satisfaz a situação medonha.

Bom aqui vejo que seria interessante abrir um tópico somente para essa discussão de Pessoa e Empresa loco que se procurarmos na net veremos que os exemplos sao grotescos, salve o artigo que tem nesse site sobre interface.

Contudo agradeço mais uma vez Sergio e aos demais que postaram aqui.
Abraços

Modelar estruturas de negocio não é fácil. No fim vc vai depender de implementar uma certa estrutura que tena na cabeça , testar e remodelar. Esse processo iterativo e ciclico acaba sendo a melhor opção.
Por outro lado, vc precisa definir os objetivos dos seus modelo ou ele será gigante.

Começar por uma interface é muito bom. Eu sempre prefiro isso. Afinal Cliente é um papel que uma pessoa desempenha (é uma “interface” no sentido que ele se apresenta de certa forma). Usar classes Abstratas que implementam os métodos mais comuns da interface tb é uma mao-na-roda.

Se vc está pensando em ter clientes estrangeiros tlv o seu modelo de Pessoa e Empresa tenha que ser bem mais genérico e tlv um campo CNPJ não faz sentido nesses casos. Tlv um campo Pais ajude a destinguir e junto com o descriminador que falei antes ajude a criar vários tipos de clientes como ClienteEmpresaNacional (que tem o campo CNPJ) e ClienteEmpresaEstrageira ( que não tem CNPJ, mas pode ter outro identiifcador) o mesmo para pessoa.
Ou tlv vc queira um campo chamado identificadorFiscal que todos os clientes têm que é um objeto IDFiscal que pode ter implementações diversas: CPF extends IDFiscal ; CNPJ extends IDFiscal ; IDInternacional extends IDFIscal. Com isto vc poupa de criar tantos tipos diferentes de clientes e concentra-se nas diferenças reais dos seus atributos.

Enfim, não é simples, e no fim é uma questão de gosto…

Esse exemplo do clienteFisica e clienteJuridica da mto pano pra manga mesmo, e ninguem tem a solucao milagrosa pro caso.

O Sergio deu otimas respostas na minha opiniao.

A minha solucao (depois de muita cabecada tbm) foi mais ou menos assim:

se vc tem pessoa fisica e juridica com muitas difierencas elas nao devem implementar a mesma interface soh por se chamarem pessoa(AlgumaCoisa), se elas sao parecidas eu usei o pattern state. O cliente possui uma referencia ao objeto TipoPessoa(ou qqr nome melhor q esse q lhe vier a cabeca - nao achei nenhum ainda) q é responsavel por manter os atributos q diferenciam as pessoas

ex:

public class TipoPessoa{

private String indicadorFiscal;

private bool isValido(){
     //verifica se é valido
}

//get,set

}

public class PessoaFisicao extends Tipopessoa{
}

public class Pessoa{

private Endereco endereco;
private TipoPessoa tipo;
}

O q eu fiz eh um pouco mais complexo, com classes CPF e CNPJ, extendendo Identificador e sendo usada como membros de TipoPessoa.

Acho q ainda esta longe de ser a solucao ideal, mas eh a melhor q eu tenho ateh agora.

Sérgio,

No seu exemplo acima, nao estou vendo muita diferença entre seu Repository e um DAO.

Se eu falei besteira, poderia me explicar a diferença?

[quote=fabiocsi]Sérgio,

No seu exemplo acima, nao estou vendo muita diferença entre seu Repository e um DAO.

Se eu falei besteira, poderia me explicar a diferença?[/quote]

Repository: Mediador entre a camada de dominio e a camada de mapeamento usando uma interface semelhante à de uma coleção* para acessar objetos do dominio. http://martinfowler.com/eaaCatalog/repository.html

DAO: Data Access Object :

Generalizar a interface de acesso a dados para diferentes mecanismos de acesso a esses dados.

Adapta a API de acesso aos dados persistidos para uma API de acesso a dados (independente de onde estão esses dados) **

http://java.sun.com/blueprints/patterns/DAO.html

  • Uma interface semelhante a uma coleção quer dizer que existem métodos que adicionam o objeto ao repositorio ( add ) , substituem o objecto por uma “copia” mais atualizada (set) , removem o objeto (remove)
    e iteram sobre uma lista de objetos do mesmo tipo (iterate)

** Adaptar interface pode significar adaptar para uma interface do tipo de listagem, mas normalmente não.

A diferença essencial é que um Repository devolve objetos de Dominio e não apenas aglomerados de dados, enquanto um DAO apenas retorna aglomerados dados e não objetos de Dominio.
O fato do repositório usar jdbc diretamente não o torna um DAO. O Objetivo do DAO é isolar/separa a API de persistência de forma que os mesmos dados possam ser persistido de formas diferentes. O objectivo do Repositorio é simular uma coleção de objetos de dominio, se ele o faz usando um Banco de Dados é um detalhe da implementação e não uma definição do que é um Repositorio.

Ummm… DAO não retorna objetos de dominio?
Entao isso quer dizer tambem que o método incluir() de um DAO tb nao recebe objetos de dominio?

Teria como vc me mostrar 1 exemplo concreto? queria muito entender isso

[quote=fabiocsi]Ummm… DAO não retorna objetos de dominio?
Entao isso quer dizer tambem que o método incluir() de um DAO tb nao recebe objetos de dominio?

Teria como vc me mostrar 1 exemplo concreto? queria muito entender isso[/quote]

Imagine que tenho um dominio onde existem clientes e pedidos dos clientes. Imagine que quero fazer um report que relacionas os dois. O repositorio permite-me acesso à lista de Cliente e à lista de Pedido. O Pedido tem um cliente associado e um cliente têm vários pedidos associados. Eu navego nesta estrutura diretamente nos objetos de domínio e o Repositório serve apenas para encontrar o objeot “raiz” da minha navegação.

Mas ao criar um report tem um monte de joins que quero fazer e um monte de campos das entidades que não me interessam. Então crio uma frase SQL que me retorne os campos para o report. Como eu não quero usar SQL diretamente e pretendo isolar o acesso a esses dados , uso um DAO. O meu dao , que obtenho de uma fabrica, é configurado externamente para ler/escrever do banco certo no dialecto sql certo. O DAO abstraem para mim os detalhes do acesso as dados, eu apenas passo um critério de procura e ele me retorna os dados. Mas ele retorna os dados em bruto e não disfarçados de objeto de dominio.
Para criar o report eu não quero ter que criar objetos Cliente nem Pedido, apenas quero um conjunto de dados de cada um. Poderia criar um objeto ResultadoDoReportClientePedido com os dados que quero e preencher esse objeto da mesma forma que preencho Cliente ou Pedido, mas ResultadoDoReportClientePedido não seria um objeto de dominio porque não tem nenhum metodo de negocio associado. É apenas um conjunto de dados.
O DAO poderia ser esperto o suficiente para retornar um objeto como este já preenchido, mas um DAO nunca será esperto para distinguir os objetos de dominio.

Entenda que a distinção entre DAO e Repositorio é muito teorica, mas existem diferenças práticas. Estamos falando de padrões e dando exemplos de objetos que implementam um padrão de cada vez. Poderiamos ter um objeto que faz as duas coisas, sendo responsável pela logica de negocio e pelo acesso aos dados. Tudo bem. Não ha problema nisso.
Mas para se possa dizer que esse objeto segue o padrão X ou Y ele tem que ter certas características. Um objecto que contém logica de negocio e acesso a dados junto , nunca será um DAO , porque o objetivo do dao
é poder ter várias implementações que acesso os mesmos dados em locais/estilosl/inguagens diferentes.
Inerante a isto está o uso de um fábrica de DAO e o não uso explicito de nenhuma das implementações possíveis. Logo, por construção e definição se o seu codigo não permite esta estrutura , isso não é DAO.

Mas um objeto que contém logica de negocio e acesso a dados junto pode muito bem ser um Repositorio.

O que precisa ser entendido é que um Repositório pode e deve conter logica de negocio. Um DAO não pode conter lógica de negocio.

Se vc entrar em http://martinfowler.com/eaaCatalog/repository.html verá um uml explicando o Repositorio. Verá que existe uma estratégia de acesso aos dados que o repositorio usa (Strategy Pattern)
Isso singifica que a estratégia pode mudar, mas as ordens e o resultado não podem mudar. Estrategias diferentes correspondem com DAOs diferentes e por isso que Repositorio e DAO não são a mesma coisa.
DAO é um padrão que permite alterar a estratégia de acesso a dados que o Repositorio usa.

Não sei como ser mais claro.

Foi bem claro.

Só mais uma pergunta sérgio:

  public List<Gerente> lista( StringBuffer sql ) throws Exception {
       
        List listaGerente = new ArrayList();
       
        try {
            
            pstmt = conn.prepareStatement( sql.toString() );
            
            rs = pstmt.executeQuery();
            
            while ( rs.next() ) {
            
                Gerente gerente = new Gerente();
                
                gerente.setId( rs.getLong("ID_GERENTE") );
                gerente.setNome( rs.getString("NM_GERENTE") );
                gerente.setEmail( rs.getString("DS_EMAIL") );
                gerente.setTelefone( rs.getString("NR_TELEFONE") );
                gerente.setRamal( rs.getString("NR_RAMAL") );
                gerente.setCelular( rs.getString("NR_CELULAR") );
                
                listaGerente.add( gerente );
                
            }
            
            return listaGerente;
            
        } catch( Exception e ) {
           
           e.printStackTrace();
           throw new Exception( "Falha ao obter lista Gerentes." );
           
        } finally {

            if ( rs != null ) rs.close();
            if ( pstmt != null ) stmt.close();
            
        }
        
    }

Baseado no que vc me explicou, o código acima nunca poderia ser método de um DAO.

A) Poderia ser método de um Repository?
B) Ou nao pode ser porcaria nenhuma e eu nem deveria fazer isso?

Se a resposta for B, explique com código se possivel como eu poderia fazer certo.

Isso não é concerteza um DAO porque não abstrai a interface de acesso aos dados ( ou seja, vc explicitamente usa JDBC). Isso sim pode ser um Repositório. O problema é que :

a)Se vc considera um repositorio, então é um repositório mal implementado porque a sua interface está dependente do método de persistência ( vc passa uma frase SQL)
b)Se vc não considera um repositorio porque está dependente do SQL, então isso não é nem um Repositório nem um DAO.

Você pode :
a) Usar esse objeto sem problema, não pode é dizer que isso é um Design Pattern , nem DAO, nem Repositorio. Mas é válido usar isso. Eu disse válido, não disse bom , nem recomendável.
b) Vc pode retirar StringBuffer e usar uma classe especial de critério. Tipo assim :

public List<Gerente> lista( CriterioDePesquisa criterio ) throws Exception {  

Essa classe é um grafo com sub-criterios. Vc pode fazer isso com o padrão Composite. Básicamente vc precisa dos critérios logico e de comparação de valores de campo. Internamente ao método vc traduz isso em num Buffer de sql e continua igual depois disso. (ao fazer isto vc estará usando outro padrão : Intrepreter)
Esta opção é melhor que (a) pois já permite dizer que esse objeto é um Repositorio pois trata os objetos Gerente como se eles estivessem numa coleção.

c) O objeto de critério é muito legal, mas pode haver critérios demasiado complicados para escrever em forma de grafo. Ai vc inclui um método no repositorio que é especifico, ou seja, ele recebe parametros da query e não a query em si. Esta opção é a melhor, vc monta o SQL internamente e só passa os parametros necessários.
Claro que assim vc precisa de um metodo para cada pesquisa. Exemplo:

public List<Gerente> listaTodos() throws Exception 
public List<Gerente> listaGerentes(int  nivel  ) throws Exception 
public List<Gerente> listaGerentesQueAtingiramMeta(Date data, Meta  meta) throws Exception 

Ummm… ficou mais claro agora…

Porém fazendo isso:

public List<Gerente> listaTodos() throws Exception   
public List<Gerente> listaGerentes(int  nivel  ) throws Exception   
public List<Gerente> listaGerentesQueAtingiramMeta(Date data, Meta  meta) throws Exception

em todos eles eu vou ter isso:

      while ( rs.next() ) {   
             
              Gerente gerente = new Gerente();   
                 
              gerente.setId( rs.getLong("ID_GERENTE") );   
              gerente.setNome( rs.getString("NM_GERENTE") );   
              gerente.setEmail( rs.getString("DS_EMAIL") );   
              gerente.setTelefone( rs.getString("NR_TELEFONE") );   
              gerente.setRamal( rs.getString("NR_RAMAL") );   
              gerente.setCelular( rs.getString("NR_CELULAR") );   
                 
              listaGerente.add( gerente );   
                 
       }

fica feio nao? :?:

[quote=fabiocsi]
em todos eles eu vou ter isso:

      while ( rs.next() ) {   
             
              Gerente gerente = new Gerente();   
                 
              gerente.setId( rs.getLong("ID_GERENTE") );   
              gerente.setNome( rs.getString("NM_GERENTE") );   
              gerente.setEmail( rs.getString("DS_EMAIL") );   
              gerente.setTelefone( rs.getString("NR_TELEFONE") );   
              gerente.setRamal( rs.getString("NR_RAMAL") );   
              gerente.setCelular( rs.getString("NR_CELULAR") );   
                 
              listaGerente.add( gerente );   
                 
       }

fica feio nao? :?:[/quote]

:shock: ora … que tal um método assim :


// algum metodo faz
      while ( rs.next() ) {   
              listaGerente.add( parse(rs));    
       }
//---

protected Gerente parse(ResultSet rs ){
             Gerente gerente = new Gerente();   
                 
              gerente.setId( rs.getLong("ID_GERENTE") );   
              gerente.setNome( rs.getString("NM_GERENTE") );   
              gerente.setEmail( rs.getString("DS_EMAIL") );   
              gerente.setTelefone( rs.getString("NR_TELEFONE") );   
              gerente.setRamal( rs.getString("NR_RAMAL") );   
              gerente.setCelular( rs.getString("NR_CELULAR") );   
                 
             return gerente;
}

Este método vc pode até substituir por algo usando Reflection e Annotations
Vai, não é assim tão feio … :smiley:

:smiley: rox

Ultima pergunta:

Digamos que eu queira usar isso com Reflection, mas sem Annotations… pode me da uma luz?

[quote=fabiocsi] :smiley: rox

Ultima pergunta:

Digamos que eu queira usar isso com Reflection, mas sem Annotations… pode me da uma luz?[/quote]

Com ou sem anotações o objetivo daquele pedaço de codigo é o quê ? É mapear os campos da tabela para os campos no objeto de dominio.
Na maioria dos casos esse mapeamento é 1 para 1 , mas não será sempre. A resposta é portanto : crie um mappeador. Este objeto tem a responsabilidade de saber como e fazer o mapeamento entre os dados no ResultSet e os campos do objeto e vice-Versa. NO caso inverso seria um mapeamento para um Statement ou um PreparedStatement.

interface DataMapper 

<T> T read(Class<T> , ResultSet rs );

Agora é s´po implementar.

Sem anotações vc precisará de um lugar onde guardar o mapeamento. A escolha obvia é XML (!) a solução mais simples
sem usar XML é covencionar que os nomes dos campos nos objectos serão os nomes nas tabelas. Isso funciona em muitos casos
mas o mapeamento XML é para casos complexos em que os campos não podem ter os mesmos nomes (por alguma razão, não interessa qual)

Então, usando reflection vc pega os métodos chamados getXXX retira o XXX , pega o XML ou outro formato qq, traduz esse XXX para YYY e usa o YYY para criar o SQL que passa para o banco. Seja usando o nome do get, o xml ou anotações o processo é basciamente o mesmo, é uma tradução de nomes. Claro, isto é o básico, tem mais coisas , como traduzir os nomes das tabelas elas mesmas , ai o nome da classe tem que ser traduzido para o nome da tabela.

Acho que não precisa ir muito longe, basta usar as anotações do JPA e implementar um mapeamento para elas. É mais ou menos linear para os casos simples. E os casos complexos vc pode sempre implementar uma função especial dentro do Repositorio.

[quote=fabiocsi]Sérgio,

No seu exemplo acima, nao estou vendo muita diferença entre seu Repository e um DAO.

Se eu falei besteira, poderia me explicar a diferença?[/quote]

Corrijam-me se eu estiver errado, mas a diferenca de um DAO e um Repository eh a finalidade de cada um. Eles podem ser implementados exatamente da mesma maneira, mas o intuito eh diferente.

O q eu faco eh usar os dois. Um repository q conhece uma interface DAO. Amanha se eu quiser mudar a forma de implementar a persistencia por tras dos repositories (deixar de usar o pattern DAO e usar qqr outro q um dia possa aparecer) meu objetos de dominio nao sofrerao em nada.