Использовать вложенные обобщенные коллекции или пользовательские промежуточные классы? - PullRequest
6 голосов
/ 08 марта 2009

Перед знакомством с дженериками в языке Java я написал бы классы, инкапсулирующие коллекции коллекций. Например:

class Account {
   private Map tradesByRegion; //KEY=Region, VALUE=TradeCollection
}

class TradeCollection {
   private Map tradesByInstrument; //KEY=Instrument, Value=Trade
}

Конечно, с помощью дженериков я могу просто сделать:

class Account {
   private Map<Region, Map<Instrument, Trade>> trades;
}

Теперь я склоняюсь к выбору варианта № 2 (более обобщенной версии варианта № 1 * *), потому что это означает, что я не получаю распространение классов, которые существуют исключительно с целью переноса Коллекция. Но у меня есть неприятное ощущение, что это плохой дизайн (например, сколько вложенных коллекций я должен использовать, прежде чем объявлять новые классы). Мнения?

Ответы [ 7 ]

4 голосов
/ 08 марта 2009

Сочетание двух. Хотя вы можете использовать универсальные шаблоны для замены пользовательских классов, вы все равно захотите использовать класс для инкапсуляции ваших концепций. Если вы просто передаете карты карт карт списков всем, кто контролирует, что вы можете добавить? кто контролирует что можно удалить?

Для хранения данных, дженерики - отличная вещь. Но вы все еще хотите, чтобы методы проверяли, когда вы добавляете торговлю или добавляете учетную запись, и без какого-либо класса, упаковывающего ваши коллекции, никто не контролирует это.

4 голосов
/ 08 марта 2009

2 лучше, потому что:

  • Меньше кода выполняет то же самое эффект (лучше, на самом деле, как в # 1 некоторая информация о вашем типе существует только в комментариях)
  • Совершенно ясно, что происходит на.
  • Ваши ошибки типа будут обнаружены во время компиляции.

Что можно порекомендовать 1? по общему признанию, к картам

2 голосов
/ 08 марта 2009

Я думаю, что лучше помнить объекты и подчеркивать коллекции немного меньше. Reification - твой друг.

Например, естественно иметь объекты Student и Course, если вы моделируете систему для школы. Где должны быть получены оценки? Я бы сказал, что они принадлежат объекту, где студенты и курс встречаются - ReportCard. У меня не было бы GradeCollection. Дайте ему реальное поведение.

2 голосов
/ 08 марта 2009

Обычно также будет некоторый код для работы с коллекциями. Когда это становится нетривиальным, я упаковываю коллекцию в новом классе. Чем глубже вложение, тем больше вероятность, что это произойдет.

2 голосов
/ 08 марта 2009

Я сделал для меня это простое правило: Никогда более двух <и двух запятых в декларации обобщения и <em>предпочтительно только одна запятая После этого я ввожу пользовательские типы. Я думаю, что это тот момент, когда читаемость страдает достаточно, чтобы оправдать дополнительные понятия.

Существует действительно веская причина избегать слишком глубоких обобщений: сложность заключается не только в фактическом объявлении, но обычно имеет тенденцию быть одинаково видимой в логике построения. Поэтому большая часть кода имеет тенденцию становиться запутанной, если вы слишком глубоко вкладываете эти объявления. Создание промежуточных классов может очень помочь. Хитрость заключается в том, чтобы часто находить подходящие промежуточные классы.

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

1 голос
/ 08 марта 2009

Я думаю, что ответ на этот вопрос заключается в том, что это зависит от ситуации. Как правило, введение типа полезно, если оно также вводит методы, связанные с типом, если эти промежуточные типы передаются независимо друг от друга и т. Д.

Вы можете найти этот небольшой совет от Rich Hickey (создателя Clojure) о создании совместимых библиотек, довольно интересный:

Он предназначен как особый совет авторам библиотеки Clojure, но я думаю, что это интересная пища для размышлений даже на Java.

1 голос
/ 08 марта 2009

Я предпочитаю # 2. Понятнее, что происходит, и он безопасен во время компиляции (я предпочитаю, чтобы во время компиляции было как можно больше ошибок, а не во время выполнения ... в общем, мне нравится, когда ничего не происходит) .

Edit:

Ну, есть два способа, которые я вижу ... Я думаю, это зависит от того, что вы будете использовать:

class Account
{
   private Map<Region, TradeCollection> tradesByRegion;
}

class TradeCollection
{
   private Map<Instrument, Trade> tradesByInstrument;
}

или

class Account<R extends Region, I extends Instrument, T extends Trade, C extends TradeCollection<I, T>> 
{
   private Map<R, C> tradesByRegion;
}

class TradeCollection<I extends Instrument, T extends Trade>
{
   private Map<I, T> tradesByInstrument;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...