У меня есть следующая карта:
Map<Double, List<SoundEvent>> soundEventCells = new HashMap<Double, List<SoundEvent>>();
Это HashMap
отображает double
значения (которые являются точками во времени) в соответствующую SoundEvent
«ячейку»: каждая «ячейка» может содержать число SoundEvent
s. Вот почему он реализован как 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>();
Это перебор? Вы бы сделали это в своих проектах?
java
design
object-oriented
Авив Кон
источник
источник
private static
тем, что он будет использоваться только внешним классом, но он не связан с каким-либо конкретным экземпляром внешнего класса. Разве это не правильное использованиеprivate static
?Ответы:
Это не излишне. Начните с необходимых операций, а не с «Я могу использовать HashMap». Иногда HashMap - это то, что вам нужно.
В твоем случае я подозреваю, что это не так. Что вы, вероятно, хотите сделать, это что-то вроде этого:
Вы определенно не хотите иметь кучу кода, говорящего это:
Или, может быть, вы могли бы просто использовать одну из реализаций Guava Multimap .
источник
TimeLine
класс именно для такого рода вещей :) Это тонкая оболочка вокругHashMap<Double, SoundEventCell>
(в конце концов, я пошел с идеейSoundEventCell
вместоList<SoundEvent>
). Так что я могу просто сделатьtimeline.addEvent(4.5, new SoundEvent(..))
и сделать инкапсулированный материал более низкого уровня :)Хотя это может помочь в удобочитаемости в некоторых областях, это также может усложнить ситуацию. Я лично отказываюсь от обертывания или расширения коллекций ради беглости, так как новая обертка, при первоначальном чтении, подразумевает для меня, что может быть поведение, о котором мне нужно знать. Считайте это оттенком принципа наименьшего сюрприза.
Придерживаться реализации интерфейса означает, что мне нужно беспокоиться только об интерфейсе. Конкретная реализация может, конечно, содержать дополнительное поведение, но мне не нужно беспокоиться об этом. Поэтому, когда я пытаюсь найти свой путь через чей-то код, я предпочитаю простые интерфейсы для удобства чтения.
Если, с другой стороны, вы находите вариант использования, который выигрывает от дополнительного поведения, то у вас есть аргумент для улучшения кода путем создания полноценного класса.
источник
List
можно сделать, и делает все это по уважительной причине.SoundEventCell
можно реализоватьIterable
дляSoundEvent
s, который будет предлагать итераторsoundEvents
члена, так что вы сможете читать (но не писать) как любой список. Я не решаюсь замаскировать сложность почти так же сильно, как не решаюсь использовать a,List
когда мне может понадобиться что-то более динамичное в будущем.Упаковка ограничивает вашу функциональность только теми методами, которые вы решили написать, в основном увеличивая свой код без пользы. По крайней мере, я бы попробовал следующее:
Вы все еще можете написать код из вашего примера.
Тем не менее, я когда-либо делал это, только когда есть некоторая функциональность, которая нужна самому списку. Но я думаю, что ваш метод был бы излишним для этого. Если у вас не было причины хотеть ограничить доступ к большинству методов List.
источник
Другое решение может состоять в том, чтобы определить ваш класс-оболочку с помощью одного метода, который предоставляет список:
Это дает вам хорошо названный класс с минимальным кодом, но все же дает инкапсуляцию, что позволяет, например, сделать класс неизменным (делая защитную копию в конструкторе и используя
Collections.unmodifiableList
в методе доступа).(Однако, если эти списки действительно используются только в этом классе, я думаю, вам лучше заменить их
Map<Double, List<SoundEvent>>
наMultimap<Double, SoundEvent>
( docs ), поскольку это часто экономит много логики проверки ошибок и ошибок.)источник