Por que definir um objeto Java usando interface (por exemplo, Mapa) em vez de implementação (HashMap)


17

Na maioria dos códigos Java, vejo pessoas declarando objetos Java como este:

Map<String, String> hashMap = new HashMap<>();
List<String> list = new ArrayList<>();

ao invés de:

HashMap<String, String> hashMap = new HashMap<>();
ArrayList<String> list = new ArrayList<>();

Por que existe uma preferência para definir o objeto Java usando a interface, em vez da implementação que realmente será usada?


Respostas:


26

O motivo é que a implementação dessas interfaces geralmente não é relevante ao manipulá-las; portanto, se você obriga o chamador a passar a HashMappara um método, então você está essencialmente obrigando qual implementação usar. Portanto, como regra geral, você deve lidar com a interface em vez da implementação real e evitar a dor e o sofrimento que podem resultar na alteração de todas as assinaturas de método HashMapquando você decidir usar LinkedHashMap.

Deve-se dizer que há exceções quando a implementação é relevante. Se você precisar de um mapa quando a ordem for importante, poderá exigir a aprovação de um TreeMapou LinkedHashMapa, ou melhor ainda, SortedMapque não especifique uma implementação específica. Isso obriga o chamador a necessariamente passar um certo tipo de implementação do Mapa e sugere fortemente que a ordem é importante. Dito isto, você pode substituir SortedMape passar por um não classificado? Sim, é claro, no entanto, esperamos que coisas ruins aconteçam como resultado.

No entanto, as práticas recomendadas ainda determinam que, se não for importante, você não deve usar implementações específicas. Isso é verdade em geral. Se você está lidando com Doge do Catqual deriva Animal, para fazer o melhor uso da herança, geralmente evite ter métodos específicos para Dogou Cat. Em vez disso todos os métodos em Dogou Catdeve substituir métodos Animale ele irá salvar-lhe problemas no longo prazo.


Quando você precisa de um mapa classificado, o tipo de parâmetro deve ser SortedMap, não TreeMap.
Cefalópode

O @Arian SortedMapé uma das várias implementações que lidam com pedidos. Isso está além do ponto. TreeMaptambém solicita itens de acordo com a implementação da chave Comparableou com uma Comparatorinterface.
6114 Neil

Não, o SortedMap não é uma implementação, é exatamente esse o ponto. É a interface para mapas que ordenam por chave.
Cefalópode

1
@Arian Ah, eu entendo o que você quer dizer. Verdadeiro, melhor SortedMap, pois isso não força uma implementação. Eu vou fazer os ajustes adequados.
911 Neil

Na verdade, um LinkedHashMapnão implementa SortedMap. As únicas subclasses de SortedMapsão ConcurrentSkipListMape TreeMap.
precisa saber é

10

Nas palavras de Layman:

A mesma razão pela qual os fabricantes de aparelhos elétricos construíram seus produtos com plugues elétricos, em vez de simplesmente descascarem cabos, e as casas vêm com soquetes de parede, em vez de descascarem cabos saindo da parede.

Ao usar plugues padrão, eles permitem conectar os mesmos aparelhos em qualquer plugue compatível da casa.

Do ponto de vista da tomada, não importa se você conecta um aparelho de TV ou um aparelho de som.

Isso torna o aparelho e o soquete mais úteis.

Tomemos, por exemplo, um método que aceite um mapa como argumento.

O método funcionará independentemente de você passar um HashMap ou um LinkedHashMap para ele, desde que seja uma subclasse de Map.

Esse é o princípio de substituição de Liskov .

No código de amostra que você forneceu, isso significa que você poderá, posteriormente, por algum motivo, alterar a implementação concreta do Hash e não precisará alterar o restante do código.

O problema com o software é que, como é relativamente fácil mudar as coisas posteriormente sem desperdício de tijolos ou argamassa, as pessoas assumem que esse tipo de pensamento antecipado não vale a pena. Mas a realidade nos mostrou que a manutenção de software é muito cara.


4

É seguir o princípio de segregação da interface (o 'I' no SOLID ). Impede que o código que usa esses objetos dependa dos métodos daqueles que não são necessários, o que torna o código menos acoplado e, portanto, mais fácil de alterar.

Por exemplo, se você descobrir mais tarde que realmente precisa de um LinkedHashMap, poderá fazer essa alteração com segurança sem afetar nenhum outro código.

No entanto, há uma troca, porque você limita artificialmente o código que pode levar seu objeto como parâmetro. Digamos que exista uma função em algum lugar que exija um HashMappor algum motivo. Se você retornar a Map, não poderá passar seu objeto para essa função. Você precisa equilibrar a probabilidade de, no futuro, precisar da funcionalidade extra da classe mais concreta, com o desejo de limitar o acoplamento e manter sua interface pública o menor possível.


3

A restrição da variável a uma interface garante que nenhum dos usos dessa variável esteja usando HashMapfuncionalidades específicas que podem não existir na interface; portanto, a instância poderá ser alterada sem preocupação posteriormente para uma implementação diferente, desde que a nova instância também implemente o interface.

Por esse motivo, sempre que você desejar usar uma interface de objetos, é sempre uma boa prática declarar suas variáveis ​​como a interface e não a implementação específica; isso vale para todos os tipos de objetos que você pode usar e que possuem uma interface. A razão pela qual você vê isso frequentemente é que muitas pessoas construíram isso como um hábito.

Dito isto, às vezes não é prejudicial deixar de usar interfaces, e a maioria de nós nem sempre segue essa regra sem nenhum dano real. É apenas uma boa prática para manter quando você sentir que o código pode ser alterado e precisar de manutenção / crescimento no futuro. É menos preocupante quando você está invadindo um código que você não suspeita que terá uma vida longa ou muita importância. Também quebrar essa regra geralmente tem uma pequena conseqüência de que mudar a implementação para outra pode exigir um pouco de refatoração; portanto, se você nem sempre a seguir, não se machucará muito, embora não haja nenhum dano real em segui-la. .

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.