Чи не зайвим буде перетворити колекцію в простий клас лише задля кращої читабельності?


15

У мене є така карта:

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

Це HashMapвідображає doubleзначення (які є моментом часу) до відповідної SoundEvent"комірки": кожна "комірка" може містити ряд SoundEvents. Ось чому він реалізований як List<SoundEvent>, тому що саме він є.

Задля кращої читабельності коду я думав про реалізацію дуже простого статичного внутрішнього класу на зразок:

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
}

І ніж декларація на карті (та багато іншого коду) виглядала б краще, наприклад:

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

Це надмірність? Ви б робили це у своїх проектах?


Можна стверджувати, що концептуально це було розглянуто в розділі Як ви могли знати, чи написали ви читабельний і легкодоступний код? Якщо ваші однолітки продовжують скаржитися на ваш спосіб робити, будь то так чи інакше, вам краще змінитись, щоб почувати себе краще
gnat

1
Що саме робить перелік звукових подій «клітиною», а не списком? Чи означає цей вибір слів означає, що клітина має або, зрештою, матиме іншу поведінку, ніж список?
х-код

@DocBrown Чому? Клас полягає в private staticтому, що він буде використовуватися тільки зовнішнім класом, але він не пов'язаний з будь-яким конкретним екземпляром зовнішнього класу. Це не саме правильне використання private static?
Авів Кон

2
@Doc Brown, Aviv Cohn: Немає тегу, який би вказував будь-яку мову, тому все може бути правильним і неправильним одночасно!
Еміліо Гаравалья

@EmilioGaravaglia: Java (я думаю, що це досить зрозуміло, оскільки, судячи з синтаксису, це може бути або Java, або C #, а використовувані конвенції звужують її до Java;)).
Авів Кон

Відповіді:


12

Це зовсім не зайве. Почніть з потрібних вам операцій, а не починаючи з "Я можу використовувати HashMap". Іноді HashMap - це саме те, що потрібно.
У вашому випадку я підозрюю, що це не так. Можливо, ви хочете зробити щось подібне:

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

Ви точно не хочете мати купу коду, який говорить про це:

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

Або , може бути , ви могли б просто використовувати один з гуави Multimap реалізацій.


Отже, ви виступаєте за використання класу, який по суті є механізмом приховування інформації, як ... механізм приховування інформації? Жах.
Роберт Харві

1
Насправді так, у мене є TimeLineклас саме для такої речі :) Це тонка обгортка навколо HashMap<Double, SoundEventCell>(зрештою, я пішов SoundEventCellзамість List<SoundEvent>ідеї). Тож я можу просто зробити timeline.addEvent(4.5, new SoundEvent(..))і інкапсульований матеріал нижчого рівня :)
Авів Кон

14

Хоча це може допомогти в читанні в деяких областях, це також може ускладнити справи. Я особисто відхиляюся від упаковки чи розширення колекцій задля безперебійності, оскільки нова обгортка при першому читанні натякає на мене, що може бути поведінка, про яку я маю знати. Вважайте це відтінком Принципу найменшого сюрпризу.

Дотримуватися впровадження інтерфейсу означає, що мені потрібно лише турбуватися про інтерфейс. Конкретна реалізація може, звичайно, спричинити додаткову поведінку, але мені не потрібно через це турбуватися. Отже, коли я намагаюся знайти свій шлях через чийсь код, я віддаю перевагу зрозумілим інтерфейсам для читабельності.

Якщо, з іншого боку, ви знаходите випадок використання, який має користь від додаткової поведінки, то у вас є аргумент для вдосконалення коду, створивши повноцінний клас.


11
Обгортка може також використовуватися для видалення (або приховування) непотрібної поведінки.
Роман Райнер

4
@RomanReiner - Я б застерігав проти таких речей. Сьогодні непотрібна поведінка часто програміст проклинає ваше ім’я завтра. Усі знають, що Listможе зробити, і все це робить з поважної причини.
Теластин

Я ціную бажання зберегти функціональність, хоча я вважаю, що рішення - це ретельний баланс між функціональністю та абстракцією. SoundEventCellможе реалізувати Iterableдля SoundEvents, який запропонував би ітератор soundEventsчлена, тож ви зможете прочитати (але не написати) як будь-який список. Я вагаюся, щоб замаскувати складність майже стільки ж, скільки я вагаюся використовувати те, Listколи мені може знадобитися щось більш динамічне в майбутньому.
Ніл

2

Обгортаючи це обмежує вашу функціональність лише тими методами, які ви вирішили написати, в основному збільшуючи код без користі. Як мінімум, я б спробував таке:

private static class SoundEventCell : List<SoundEvent>
{
}

Ви все ще можете написати код зі свого прикладу.

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

Однак, я це робив лише тоді, коли є якийсь функціонал, який потрібен саме цьому списку. Але я думаю, що ваш метод був би надмірним для цього. Якщо у вас не було причин хочете обмежити доступ до більшості методів Списку.


-1

Іншим рішенням може бути визначення класу обгортки за допомогою одного методу, який відкриває список:

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

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

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

Це дає вам ваш добре названий клас з мінімальним кодом, але все ж дає інкапсуляцію, що дозволяє, наприклад, зробити клас незмінним (роблячи захисну копію в конструкторі та використовуючи Collections.unmodifiableListв аксесуарі).

(Однак якщо ці списки справді використовуються лише в цьому класі, я думаю, вам краще буде замінити свої Map<Double, List<SoundEvent>>на Multimap<Double, SoundEvent>( docs ), оскільки це часто економить багато логіки та помилок перевірки нуля.)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.