"sergiotaborda":
Ah! agora entendi o seu ponto. Vc acha que isso são pesquisas especializadas.
Não. São 3 métodos fazendo a mesma pesquisa e retornando informações diferentes dela.
Em um projeto onde vc tivesse a pesquisa "usuáriosAtivos" vc teria
findUsuariosAtivos : List
getFirstusuarioAtivo : usuario
countUsuariosAtivos : int
Para cada pesquisa vc teria 3 metodos. Para N pesqusias vc teria 3N métodos.
Com o outro modelo vc agrupa os métodos em um objeto de retorno. Então vc tem N pesquisas e N métodos.
muito mais simples , não ?
Pera lá então: no seu exemplo temos somente 1 tipo de busca. O que varia são os tipos de retorno. Um Retorna a Collection outro a entidade fora da collection e o outro um número (inteiro) possívelmente.
3 métodos, 1 tipo de busca.
Com isto realmente teriamos muito código duplicado e o problema da manutenabilidade como você disse. Porém, o "outro modelo" que você citou eu não entendi bem como poderia especificar ao método do Repositório que eu quero um getFirstusuarioAtivo ou que eu quero um countUsuariosAtivos.
public class Repositorio {
public QueryResult findActive(){
// não executa nada
return new SQLQueryResult (datasource);
}
}
public class SQLQueryResult <T> implements QueryResult<T>{
DataSource datasource;
ListQueryResult (DataSource datasource{
this.datasource = datasource;
}
public T find (){
ResultSet rs = execute("SELECT TOP 1 * FROM table ... ");
if (rs.next){
return readObject(rs);
} else {
return null;
}
}
public Collection<T> list(){
ResultSet rs = execute("SELECT * FROM table ... ");
List all = new ArrayList();
while (rs.next){
all.add(readObject(rs));
}
return Collections.unmodifiableCollection(all);
}
public int count (){
ResultSet rs = execute("SELECT count(1) FROM table ... ");
rs.next
return rs.getInt(1);
}
public boolean isEmpty (){
return this.count() == 0;
}
}
Veja, no seu exemplo eu usaria o que para dizer ao findActive() que eu quero chamar o find() que me retornará um TOP 1 por exemplo ?
"sergiotaborda":
Não. Nada disso.
O QueryObject não faz nada. Ele é apenas um conjunto de dados. Um criteria do hibernate é um QueryObject.
O String SQL passado no statement é um QueryObject.
Legal, até aqui eu entendi. No meu pensamento o QueryObject mandava a DAO passear, mas depois da sua explicação eu percebi que ele manda o Repositório passear.
Ao que entendi, o Repositório está para nos servir com Objetos da persistência e agora também evitar um monte de Criteria espalhadas pelas Actions.
Se eu entendi corretamente, uma implementação possível seria:
public class Repositorio {
public Result findAtivos(int porCep) {
// monta a o critério/query object
// passa ao criteria a espeficicação de que queremos por cep
ResultSet rs = usuariosDao.find(Criteria);
// monta o list/collection ou transmite uma info de não localizada
}
}
Minha Action chamaria o Repositório - nesse caso acho que não precisaria de Serviço:
public class AlgumacoisaAction {
public static void main(String..) {
Repositorio repo = new Repositorio;
int cep = 12345678;
repo.findAtivos(cep);
}
}
Dessa forma eu não exibiria a implementação dos critérios de busca, evitaria um monte de Criterio nas Actions.
Eu apenas não entendi como poderia fazer meu Repositório buscar de formas diferentes uma mesma informação, assumindo o exemplo acima...
public class Repositorio {
public Result findAtivos(int porCep) {
// monta a o critério/query object
// passa ao criteria a espeficicação de que queremos por cep
ResultSet rs = usuariosDao.find(Criteria);
// monta o list/collection ou transmite uma info de não localizada
}
public int countAtivos(int porCep) {
//monta o critério
// passa ao critéria o cep
int rs = usuariosDao.count(Criteria);
// retorna isto
}
}
public class AlgumacoisaAction {
public static void main(String..) {
Repositorio repo = new Repositorio;
int cep = 12345678;
repo.findAtivos(cep);
int totalAtivoPorCep = repo.countAtivos(cep);
}
}
Ao que entendi, minha DAO é melhor aproveitada, porém eu teria 3n Métodos no Repositório para n pesquisas especializadas. Justamente o que não é ideal para a manutenabilidade. =(
Pois se eu precisasse fazer uma busca por inativos, eu teria que adicionar no repositório mais 3 métodos. findInativos(); listInativos(); countInativos(); A DAO ficaria com os 3 de sempre, penso.
"sergiotaborda":
Agora, o QueryObject tende a ser mais complexo. A ideia é vc poder pedir aquelas 4 informações de forma combinada algo assim
QueryObject q = QueryObject.for(Product.class). where("name").eq(name). and("active").isTrue(). and("selled").in(intervalo)
Ai vc passa para o método find() e pronto. Bácisamente o seu repositorio começa a ter um só método. Só que isso destroi o repositorio. O objectivo do repositorio é manter e conter a contrução do QueryObject
Entendi. A idéia do QueryObject é não ter aquela chuva de pesquisa no Repositório, logo, isso acaba com a utilidade do mesmo. Entretanto, teremos QueryObject esparramadas em todas Actions. Se precisar alterar algo algum dia, ferrou ! Mas vem cá, o hibernate não trabalha exatamente assim ?
"sergiotaborda":
aposto que isso não era um repositorio e sim um DAO. Pela simples razão que os repositorios não recebem QueryObject complexos ( como já expliquei ) e Criteria é um objeto complexo.
Isso que vc descreveu é o que o um DAO ou um DomainStore faria.
Sim, era um repositório! Veja na imagem: http://helio.hlegius.pro.br/imagens/oop/repository_de_acordo_com_livro.jpg
"sergiotaborda":
A Criteria que foi enviado ao objeto veio de onde ?
Veio da Action.
"sergiotaborda":
Foi montada por quem ?
Pela Action.
"sergiotaborda":
Quem escolheu os parametros para ela ?
Possivelmente poderia ter sido o usuário utilizando-se da interface selecionou os campos a serem filtrados, porém, novamente a Action que tratou essa informação e criou a criteria.
"sergiotaborda":
Em um sistema como Repositorio , seria o repositorios a fazer isso e a invocar esse objeto que vc descreveu.
em um sistema sem Repositorio , básicamente qualquer classe pode invocar o DAO, logo a construção do Criteria está espalhada pelo sistema inteiro. E isso é um problema. Esse é o problema que o repositorio tenta resolver. ele é um cara "acima" do DAO que sabe como criar Criterias , invocar o DAO, e tratar o resultado.
Isso reforça a idéia: repositório ajuda na manutenção das instruções da Dao.
"pcalcado":
Um Repositório é uma ilusão de coleção de objetos, não alguém que responde à queries. Se você quer saber quantos objetos estão dentro de um repositório provavelmente para o cliente isto é apenas um atributo deste, não o resultado de uma pesquisa.
Isso ! No caso, aliás, no meu caso, geralmente eu preciso de um "count()" para retornar informações para paginações ou/e exibir informações adicionais na interface, como por exemplo: "Vendo X registros de um total de 400". Em ambos casos, eu precisaria fazer um find() especializado naquele filtro + um count() para saber quantos são os registros todos (sem filtros).
Neste caso Phillip, o que poderia eu fazer ? Implementar o count() no repositório retornando um "Int" ao que entendi, você não é muito a favor, mas eu ainda não consigo ver outra solução...
"pcalcado":
E antes de partir para QueryObject, algo *bem* inra-estrutura e fora de DDD, siga a suestão do Evans e faça a dobradinha Specificaction/Repository
Seguirei sem dúvidas. Até por que, se eu for criar um queryobject e suas criterias é melhor eu usar algo pronto, como hibernate...
"pcalcado":
Agora se você ainda não leu o livro eu recomendo que o faça antes de tentar qualquer coisa com Domain-Driven Design. Existem muitas fontes de informação completamente distorcidas por aí.
Farei assim que possível. A grande questão é que apenas fora do país tem esse livro disponível, e as lojas nacionais têm um prazo altíssimo para "possível" entrega do mesmo. Isso quebra as pernas =(