É exagerado envolver uma coleção em uma classe simples apenas para melhor legibilidade?

15

Eu tenho o seguinte mapa:

Map<Double, List<SoundEvent>> soundEventCells = new HashMap<Double, List<SoundEvent>>();

Esses valores de HashMap maps double (que são pontos no tempo) para a célula SoundEvent 'correspondente': cada 'cell' pode conter um número de SoundEvent s. É por isso que é implementado como List<SoundEvent> , porque é exatamente isso.

Por uma questão de melhor legibilidade do código, pensei em implementar uma classe interna estática muito simples da seguinte forma:

private static class SoundEventCell {
    private List<SoundEvent> soundEvents = new ArrayList<SoundEvent>();
    public void addEvent(SoundEvent event){
        soundEvents.add(event);
    }
    public int getSize(){
        return soundEvents.size();
    }
    public SoundEvent getEvent(int index){
        return soundEvents.get(index);
    }
    // .. remove() method unneeded
}

E que a declaração do mapa (e muitos outros códigos) ficaria melhor, por exemplo:

Map<Double, SoundEventCell> soundEventCells = new HashMap<Double, SoundEventCell>();

Isso é um exagero? Você faria isso em seus projetos?

    
por Aviv Cohn 17.09.2014 / 16:32
fonte

4 respostas

12

Não é nada demais. Comece com as operações que você precisa, ao invés de começar com "Eu posso usar um HashMap". Às vezes, um HashMap é exatamente o que você precisa.
No seu caso, suspeito que não seja. O que você provavelmente quer fazer é algo assim:

public class EventsByTime {
    public EventsByTime addEvent(double time, SoundEvent e);
    public List<SoundEvent> getEvents(double time);
    // ... more methods specific to your use ...
}

Você definitivamente não quer ter um monte de código dizendo isso:

List<SoundEvent> events = eventMap.get(time);
if (events == null) {
   events = new ArrayList<SoundEvent>();
   eventMap.put(time, events);
}

Ou talvez você possa usar apenas uma das Multimap da Guava implementações.

    
por 17.09.2014 / 23:28
fonte
13

Embora possa ajudar na legibilidade em algumas áreas, também pode complicar as coisas. Pessoalmente, evito embrulhar ou estender as coleções em prol da fluência, pois o novo invólucro, na leitura inicial, implica para mim que pode haver um comportamento do qual preciso estar ciente. Considere isso como uma sombra do Princípio de Menor Surpresa.

Manter a implementação da interface significa que eu só preciso me preocupar com a interface. A implementação concreta pode, naturalmente, abrigar comportamentos adicionais, mas eu não deveria precisar me preocupar com isso. Então, quando estou tentando encontrar o caminho do código de alguém, prefiro as interfaces simples para legibilidade.

Se, por outro lado, você está encontrando um caso de uso que faz se beneficiar do comportamento adicionado, então você tem um argumento para melhorar o código criando uma classe completa.

    
por 17.09.2014 / 17:07
fonte
2

Delimitá-lo limita sua funcionalidade a apenas os métodos que você decide escrever, basicamente aumentando seu código para nenhum benefício. No mínimo, eu tentaria o seguinte:

private static class SoundEventCell : List<SoundEvent>
{
}

Você ainda pode escrever o código do seu exemplo.

Map<Double, SoundEventCell> soundEventCells = new HashMap<Double, SoundEventCell>();

Dito isso, eu só fiz isso quando há alguma funcionalidade que a própria lista precisa. Mas acho que seu método seria exagerado. A menos que você tenha um motivo para limitar o acesso à maioria dos métodos da Lista.

    
por 17.09.2014 / 22:15
fonte
-1

Outra solução pode ser definir sua classe wrapper com um único método que expõe a lista:

private static class SoundEventCell
{
    private List<SoundEvent> events;

    public SoundEventCell(List<SoundEvent> events)
    {
        this.events = events;
    }

    public List<SoundEvent> getEvents()
    {
        return events;
    }
}

Isso oferece a você uma classe bem-cotada com código mínimo, mas ainda oferece encapsulamento, permitindo, por exemplo, torne a classe imutável (fazendo uma cópia defensiva no construtor e usando Collections.unmodifiableList no acessador).

(No entanto, se essas listas estiverem sendo usadas apenas nessa classe, acho melhor substituir seu Map<Double, List<SoundEvent>> por Multimap<Double, SoundEvent> ( docs ), já que muitas vezes economiza muitos erros e lógicas de verificação de nulos.

    
por 17.09.2014 / 23:14
fonte