Responsabilidades e Coleções

Fala galera…

Me sinto eXtremamente diconfortável em implementar laços de iteração para fazer buscas em coleções. Acho que isso acaba com a divisão de responsábilidade, fere nosso amigo GRASP “especialista na informação” pelo simples fato: É a coleção que os elementos então a coleção que deveria buscar em si mesmo, so deveriamos passar um criterio de busca para ela.

Não sei se foi um sonho ou se vi ou ouvi algo que tem como passar um comparador para uma coleção e ela te retornar os elementos que atendem a esse comparador.

Já procurei bastante e ainda não vi como fazer isso em uma coleção, mas não me conformo em não ter algo como isso.

Vcs sabem como fazer isso?

[Editado]
Será que não tem um iterator que possa receber um comparator?
[/Editado]

Você pode estender a coleção e fazer o que quiser com ela. Algumas situações eu já montei classes que estendem/implementam collections.

Eu sei que todo mundo já sabe, mas eu repito de novo :). Delegação é melhor que herança - para adicionar funcionalidade a uma collection o melhor é implementar a interface Collection e delegar as operações para um objeto que representa a collection de verdade. Para facilitar dá para fazer uma subclasse de AbstractCollection usando o mesmo esquema. (O Effective Java tem um ótimo exemplo dos problemas de herdar direto da classe que se deseja “extender”, e ele até usa uma collection do java no exemplo).

Se tratandod e modelagem de domínio, este caso você deve usar um Repositório ou outra coisa que tenha sentido na sua modelagem. Uma Collection (List, vetor, Set, blablabla) é uma estrutura de dados apenas, não faz muito sentido ela ser customizada e até mesmo utilizada no seu negócio. Descubra qual conceito naquele domínio que realmente representa ‘um agrupamento de objetos x’.

Se estamos falando de OO por OO, uma boa maneira de resolver isso é a forma como Ruby e outras linguagens com closures tratam coleções. Em vez de iterar pela coleção, cria um método que recebe um algoritmo (que eu Ruby seria um block) selecionados. Em Java você pode fazer isso utilizando o padrão Visitor, onde a sua coleção recebe um Visitor e retorna uma sublista (ou apenas um elemento) com itens que obedecem à comparação feita pelo Visitor.

Eu sei que todo mundo já sabe, mas eu repito de novo :). Delegação é melhor que herança - para adicionar funcionalidade a uma collection o melhor é implementar a interface Collection e delegar as operações para um objeto que representa a collection de verdade. Para facilitar dá para fazer uma subclasse de AbstractCollection usando o mesmo esquema. (O Effective Java tem um ótimo exemplo dos problemas de herdar direto da classe que se deseja “extender”, e ele até usa uma collection do java no exemplo).[/quote]

Quer discutir um pouco Delegação vs Herança?? Se quiser, vc prefere abrir um topico para isso?

!!!Quem sabe o shoes e Rodrigo tbem opnem nessa questão!!!

Só para iniciar: Vejo muitas pessoas evitando ao maximo herança! Sera que ela é tão ruim assim? Vejo que em alguns lugares não tem efeito negativo aplicar herança que é o caso estender um iterator para passar um coparador para ele e fazer uma iteração diferenciada.

Poxa não intendi muito bem por que eu não posso utilizar uma colection como estrutura de dados na minha camada de negocio se ela faz realmente o que eu quero?

Por que não fazer um iterador que recebe um comparador (Um criterio) que personalize minha iteração?

Bem, já existe uma coisa bem parecida com isso implementada no Commons Collections (na verdade, é quase o que o Phillip sugeriu).

Você cria um Predicate que diga “como” o seu objeto deve ser e passa a coleção e o Predicate pra o método “filter()”, ele vai retornar todos os objetos que passarem no teste do Predicate.

A pergunta é: ela faz o que você quer? Se ela é apenas uma lista de objetos sim, você pode utilizar, mas se você deseja uma lsita com conhecimento sobre regra de negócios, não.

Isto é exatamente o mesmo princípio do Visitor, só que você não está mantendo essa responsabilidade na coleção.

[quote=pcalcado][quote=brunohansen]
Poxa não intendi muito bem por que eu não posso utilizar uma colection como estrutura de dados na minha camada de negocio se ela faz realmente o que eu quero?
[/quote]

A pergunta é: ela faz o que você quer? Se ela é apenas uma lista de objetos sim, você pode utilizar, mas se você deseja uma lsita com conhecimento sobre regra de negócios, não.
[/quote]

Verdade, mas faço duas ressalvas. Uma é que às vezes se deseja expandir a funcionalidade das coleções de maneira genérica, sem ligação com o domínio (um exemplo seria uma collection que filtra por predicados como sugerido). Outra é que talvez um RepositorioDeUsuarios implements Collection<Usuario> faça sentido no domínio, com as vantagens e as desvantagens que advém de poder usar objetos do Repositorio quando se espera coleções.

[quote=Maurício Linhares]Bem, já existe uma coisa bem parecida com isso implementada no Commons Collections (na verdade, é quase o que o Phillip sugeriu).

Você cria um Predicate que diga “como” o seu objeto deve ser e passa a coleção e o Predicate pra o método “filter()”, ele vai retornar todos os objetos que passarem no teste do Predicate.[/quote]

Muito boa dica sobre o filter !!! Basicamente é isso o que eu quero!!!

Agora acho que ela é um pouco diferente que o Philip sugeriu, pois ele sugeriu um visitor e o filter que vc me passou é bem diferente de um visitor. Mas cada arquiteto tem um jeito de implementar a mesma coisa.

Muito obrigado mesmo seu filter vai ajudar pacas

Acho que ela é o que realmente eu quero, so basta eu ter uma forma de plugar uma regra de negocio nela como usar o filter do mauricio ou a colection aceitar um visitor como vc sugeriu. Note que nesses dois casos eu utilizo a colection com uma regra de negocio e a colection nem se da conta disso. Com esta visão mesmo que eu queria uma colection com conhecimento de regra de negocios eu ainda sim posso usar as colection do java pos as regras são plugaveis.

[quote=pcalcado]
Isto é exatamente o mesmo princípio do Visitor, só que você não está mantendo essa responsabilidade na coleção.[/quote]

No visitor vc tambem não mante essa responsabilidade na coleção vc mante a responsabilidade no visitor, concorda?

Ae shoes desculpa se estou questionando muito mas é que eu acho muito legal conflitar minhas idéias com as suas, do mauricio, do allmighy enfim com a de todos que tem muito mais experiencia do que eu! Assim eu aprendo muito com vcs!

[quote=brunohansen]
No visitor vc tambem não mante essa responsabilidade na coleção vc mante a responsabilidade no visitor, concorda?[/quote]

Uhm… não.

Pelo que entendi do seu iterador o cliente da coleção percorre-a utilizando este iterador customizado.

Com um visitor você pede à coleção que o retorne um subconjunto, contendo todos os elementos que atendem ao algoritmo do visitor.

O Visitor não tem que saber se est´sendo aplicado a uma coleção, muito menos como iterar sobre ela. A coleção customizada vai iterar sobre si propria chamando algo como visitor.visit(get(i)) que vai retornar true ou false. Se true o objeto obedece o critério estabelecido e deve ser incluído na subcoleção.

Sim!

Então neste caso a regra de negocio estaria implementada no visitor não na coleção, ou seja, a regra de negocio estaria fora da coleção.

[quote=pcalcado]
O Visitor não tem que saber se est´sendo aplicado a uma coleção, muito menos como iterar sobre ela. A coleção customizada vai iterar sobre si propria chamando algo como visitor.visit(get(i)) que vai retornar true ou false. Se true o objeto obedece o critério estabelecido e deve ser incluído na subcoleção.[/quote]

Boa visão essa! Apartir disso eu vejo que tem duas responsábilidades diferentes uma iterar respeitando um criterio e obter uma subcoleção respeitando um criterio. A primeira eu faria um iterador e a segunda eu concordaria com vc e faria um visitor