Jump to content
Nazgulled

Quando usar List<E> em vez de uma das suas subclasses?

Recommended Posts

Nazgulled

Tenho uma vaga ideia de algo que o prof falou na aula mas já não me recordo bem do que ele disse pelo que preciso da vossa ajuda a tentar compreender os melhores casos para se usar o que irei falar de seguida.

Por exemplo, todos sabemos que a classe ArrayList<E> vem do interface List<E> e HashSet<E> e TreeSet<E> do interface Set<E>. Por sua vez, os interfaces List<E> e Set<E> vêem do interface Collection<E>. Imaginemos agora uma classe que tem uma variável privada que é um ArrayList<String> e um conjunto de métodos para devolver o estado interno desta lista e ainda adicionar/remover elementos, etc, o habitual/necessário para qualquer que seja o propósito da nossa lista.

A vaga ideia que eu tenho de algo que o prof falou é que em certas situações, deveria usar Collection<String> em vez do ArrayList<String> que é como a nossa lista está definida. Isto porque no futuro, poderíamos facilmente alterar a nossa ArrayList<String> para TreeSet<String> sem ser necessário alterar muito mais código da classe.

O que eu não sei, é, em que casos devemos realmente usar Collection<String> em vez de ArrayList<String>.

Nos métodos que recebem uma lista como argumento?

Nos métodos que devolvem uma lista?

Nos métodos que recebem uma lista como argumento e ainda devolvem uma lista?

No fundo resume-se a: em que situações, nos métodos, devo usar Collection<String> em vez de ArrayList<String> para que no futuro, se precisar de alterar de ArrayList para TreeSet ou HashSet (ou outro qualquer, estes são meros exemplos), o possa fazer sem ter que alterar muito mais o código?

EDIT:

Pequeno erro corrigido nos interfaces, estava a confundir o List com o Collection.

Share this post


Link to post
Share on other sites
Rui Carlos

Se tu vais receber uma lista como argumento, e apenas precisas de métodos que uma Collection implementa, por que razão vais obrigar o programador a passar um ArrayList, HashSet, etc. ao teu método? O mais sensato será pedir o tipo de dados mais simples, que fornece os métodos que necessitas, pois condiciona menos quem usa o teu método.

No caso dos valores devolvidos, a questão não é tão simples, pois tens que pensar naquilo que quem utilizar o teu método vai querer fazer com o dados que tu lhe devolves. Aí, talvez faça mais sentido devolver tipos de dados mais específicos, se vires que quem os vais usar, pode tirar partido de métodos que um tipo de dados mais específico implementa.

Share this post


Link to post
Share on other sites
Baderous

O que ele falou é que nos métodos em que se usam Lists ou Sets ou Maps, trabalhas internamente com o caso mais específico que te interessa, seja ele ArrayList, TreeSet, TreeMap, HashMap, HashSet, wtv, e depois devolves o valor como se fosse um List/Set/Map.

Ex:

public List<String> listaNomes() {
ArrayList<String> noms = new ArrayList<String>();
for (String nome : paises.keySet())
	noms.add(nome);
return noms;
}

Share this post


Link to post
Share on other sites
Nazgulled
No caso dos valores devolvidos, a questão não é tão simples, pois tens que pensar naquilo que quem utilizar o teu método vai querer fazer com o dados que tu lhe devolves. Aí, talvez faça mais sentido devolver tipos de dados mais específicos, se vires que quem os vais usar, pode tirar partido de métodos que um tipo de dados mais específico implementa.

Mas neste caso, não basta o utilizador fazer um casting?

Supondo que devolvo uma Collection, se ele precisar de um tipo mais específico, não bastava fazer um casting para esse tipo específico ao resultado do meu método?

@Baderous

E por exemplo, imagina esta classe que falei no inicio (que tem um ArrayList<String>). Percebi o teu exemplo no caso de retornar a lista, usaste o List<String>, até aqui tudo bem. Agora imagina o construtor desta classe que recebe uma lista. Devo declarar a assinatura do construtor a receber um parâmetro do tipo List<String> ou ArrayList<String>?

Share this post


Link to post
Share on other sites
Knitter

No caso dos valores devolvidos, a questão não é tão simples, pois tens que pensar naquilo que quem utilizar o teu método vai querer fazer com o dados que tu lhe devolves. Aí, talvez faça mais sentido devolver tipos de dados mais específicos, se vires que quem os vais usar, pode tirar partido de métodos que um tipo de dados mais específico implementa.

Se o objectivo é não condicionar o que o programador vai poder fazer então é melhor devolver a interface, dessa forma quem obtém os dados faz o que quiser com eles e adapta-os como quer.

No caso da estrutura ser declarada e controlada por ti, então os métodos devem devolver a interface, caso a estrutura possa ser declarada externamente e passada depois para a classe, então os construtores devem receber a interface e os métodos de manipulação não devem assumir nada quanto à instância especifica que a variável recebeu.

Mas a variável deve ser sempre declarada como sendo da interface, dessa forma, até para ti é mais simples trocar a implementação interna.

Share this post


Link to post
Share on other sites
Knitter

Supondo que devolvo uma Collection, se ele precisar de um tipo mais específico, não bastava fazer um casting para esse tipo específico ao resultado do meu método?

Não, para fazer cast tens de saber qual a representação interna real. Imagina que instanciaste um ArrayList, eu não posso fazer cast disso para LinkedList.

E por exemplo, imagina esta classe que falei no inicio (que tem um ArrayList<String>). Percebi o teu exemplo no caso de retornar a lista, usaste o List<String>, até aqui tudo bem. Agora imagina o construtor desta classe que recebe uma lista. Devo declarar a assinatura do construtor a receber um parâmetro do tipo List<String> ou ArrayList<String>?

Como disse acima, deves receber a interface, dessa forma podes enviar para o construtor a instancia que mais relevante for para o código.

Share this post


Link to post
Share on other sites
Rui Carlos

Se o objectivo é não condicionar o que o programador vai poder fazer então é melhor devolver a interface, dessa forma quem obtém os dados faz o que quiser com eles e adapta-os como quer.

Sim, deves usar uma interface. Mas por vezes tens várias à escolha.

Por exemplo, um SortedSet é um Set, e este por sua vez é uma Collection, como tal podias sempre devolver uma Collection. Mas para quem vai usar o resultado, podem ser úteis os métodos implementados pelo SortedSet (e que não são implementados pelo Set). Mas claro que isto limita o programador, pois deixa de poder trocar um TreeSet por um HashSet na implementação do método sem mudar a sua assinatura.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.