Ouvi o argumento de que você deve usar a interface mais genérica disponível para não ficar vinculado a uma implementação específica dessa interface. Essa lógica se aplica a interfaces como java.util.Collection ?
Prefiro ver algo como o seguinte:
List<Foo> getFoos()
ou
Set<Foo> getFoos()
ao invés de
Collection<Foo> getFoos()
No último caso, não sei com que tipo de conjunto de dados estou lidando, enquanto nos dois primeiros casos posso fazer algumas suposições sobre ordenação e exclusividade. O java.util.Collection tem uma utilidade além de ser um pai lógico para conjuntos e listas?
Se você encontrasse o código que empregava o Collection ao fazer uma revisão de código, como você determinaria se seu uso é justificado e que sugestões você faria para substituí-lo por uma interface mais específica?
Collection<List<?>>
? Fale sobre horror de codificação!Respostas:
Abstrações vivem mais que implementações
Em geral, quanto mais abstrato for o seu design, maior será a probabilidade de permanecer útil. Portanto, como o Collection é mais abstrato do que as subinterfaces, é mais provável que um design de API baseado no Collection permaneça útil do que um baseado no List.
No entanto, o princípio geral é usar a abstração mais apropriada . Portanto, se sua coleção deve suportar elementos ordenados, solicite uma Lista, se não houver duplicatas, solicite um Conjunto e assim por diante.
Uma observação sobre o design genérico da interface
Como você está interessado em usar a interface Collection com genéricos, você pode ajudar o seguinte. O Java eficaz de Joshua Bloch recomenda a seguinte abordagem ao projetar uma interface baseada em genéricos: Producers Extend, Consumers Super
Isso também é conhecido como regra do PECS . Essencialmente, se coleções genéricas que produzem dados são passadas para sua classe, a assinatura deve ter a seguinte aparência:
Assim, o tipo de entrada pode ser E ou qualquer subclasse de E (E é definido como uma super e subclasse própria na linguagem Java).
Por outro lado, uma coleção genérica que é passada para consumir dados deve ter uma assinatura como esta:
O método lidará corretamente com qualquer superclasse de E. No geral, o uso dessa abordagem tornará sua interface menos surpreendente para seus usuários, pois você será capaz de transmitir
Collection<Number>
eCollection<Integer>
tratá-los corretamente.fonte
A
Collection
interface e a forma mais permissivaCollection<?>
são ótimas para os parâmetros que você aceita. Com base no uso na própria biblioteca Java , é mais comum como um tipo de parâmetro do que um tipo de retorno.Para tipos de retorno, acho que seu argumento é válido: se é esperado que as pessoas o acessem, elas devem saber a ordem (no sentido Big-O) da operação que está sendo executada. Eu iterava sobre um
Collection
retorno e o adicionava a outra coleção, mas parece um pouco louco chamácontains
-lo, sem saber se é uma operação O (1), O (log n) ou O (n). Obviamente, apenas porque você tem umSet
, não significa que seja um hashset ou um conjunto classificado, mas em algum momento você fará suposições de que a interface foi implementada razoavelmente (e, em seguida, você precisará ir para o plano B, se você presumir mostrado incorreto).Como Tom menciona, às vezes você precisa retornar um
Collection
para manter o encapsulamento: Você não deseja que os detalhes da implementação vazem, mesmo se você puder retornar algo mais específico. Ou, no caso de Tom mencionar, você pode retornar o contêiner mais específico, mas precisará construí-lo.fonte
Eu olhava para ele do ponto de vista oposto completo e perguntava:
É muito fácil justificar isso. Você usa a lista quando precisa de alguma funcionalidade que não é oferecida por uma coleção. Se você não precisa dessa funcionalidade extra - que justificativa você tem? (E não compro "prefiro ver")
Existem muitos casos em que você usará uma coleção para fins somente leitura, preenchendo tudo de uma só vez, repetindo-o completamente - você precisa indexar manualmente a coisa?
Para dar um exemplo real. Digamos que eu execute uma consulta simples em um banco de dados. (
SELECT id,name,rep FROM people WHERE name LIKE '%squared'
) Pego de volta os dados relevantes, preencho objetos Person e os coloco em uma PersonList)Então, que justificativa eu teria para esses métodos extras? (que, de qualquer maneira, não seria implementado na minha PersonList)
fonte