Есть ли причина избегать дозорного паттерна в Java? - PullRequest
5 голосов
/ 10 ноября 2009

Я слышал, что люди советуют всегда использовать шаблон Iterator для управления циклами, а не создавать исключение (как это делается в Python итераторах ) или использовать Sentinel pattern , посредством которого возвращается специальное значение часового (часто null), указывающее конец итерации.

Передовая практика советует против дозорного образца? Если так, то почему? (кроме того, что он не работает с синтаксисом foreach в Java 1.5).

Edit: Пример кода 1 - Sentinel Pattern

Reader r = ...;
for( int val = r.read(); val != -1; val = r.read()) {
   doSomethingWith(val);
}

Пример кода 2 - Шаблон итератора

for(Iterator<Thing> it = getAnIterator() ; it.hasNext(); ) {
  Thing t = it.next();
  doSomethingWith(t);
}

Ответы [ 7 ]

15 голосов
/ 10 ноября 2009

Проблема с шаблоном Sentinel заключается в том, что он явно исключает значение часового из набора значений, которые являются допустимыми элементами. То есть, если у вас есть список объектов, которые могут корректно содержать значение null в качестве элемента, использование значения null в качестве значения часового является неудачей.

9 голосов
/ 10 ноября 2009

Исключения следует использовать только в «исключительных» ситуациях. Завершение или разрыв цикла - это нормальный программный поток, а не исключительная ситуация.

Кроме того, при работе на Java (или на любом другом языке) вы хотите использовать шаблоны и соглашения, которые являются общепринятыми и общеизвестными в сообществе, поскольку другим программистам на Java может потребоваться поддерживать ваш код. Если они это сделают, они, скорее всего, ожидают увидеть Итераторы, а не образец стража.

4 голосов
/ 10 ноября 2009

Я думаю, что они оба в порядке, но Iterator более идиоматичен в Java (особенно если у вас действительно есть Iterable, который вы можете использовать вместо цикла for-each).

Единственное место, где вы часто видите версию Sentinel на Java, это именно тот случай, когда вы написали код ввода / вывода.

2 голосов
/ 10 ноября 2009

Мантра «говори, что делаешь, и делай, что говоришь».

Если вы проверяете возвращаемое значение как особое значение, это ничего не говорит о том, почему вы проверяете это. В вашем примере:

for( int val = r.read(); val != -1; val = r.read()) {
   doSomethingWith(val);
}

Означает ли это, что «если возвращаемое значение когда-либо становится -1, мы можем пропустить остальные», или «если возвращаемое значение равно -1, произошла ошибка», или «если возвращаемое значение когда-либо равно -1 , конец достигнут "? Напротив, hasNext совершенно однозначно.

Кстати, мне действительно нравятся конструкции foreach и map, которые другие языки предоставляют (или позволяют писать) лучше, чем явные циклы.

2 голосов
/ 10 ноября 2009

Шаблон Sentinel используется в JDK для чтения потоков, поэтому он не является неслыханным, но неудобно делать из него цикл. Все решения имеют негативы, которых нет у итератора. Ваше решение требует повторного вызова для чтения (то есть дублирование кода). Цикл while заставляет переменную объявляться вне области действия цикла. Другие альтернативы были бы удивительными и трудными для подражания.

Таким образом, в конце концов, итератор является своего рода значением по умолчанию, от которого следует отклоняться только по причине.

0 голосов
/ 10 ноября 2009

"Исключения следует использовать только в" исключительных "ситуациях. Завершение или разрыв цикла - это нормальный программный поток, а не исключительная ситуация."

Если чтение файла успешно выполняется миллион раз и только в последний раз он говорит: «Я не могу найти больше записей», вы не называете это «исключительным»?

Я не вижу проблемы в использовании, скажем, EOFExceptions для потока управления (если Система достаточно здравомыслящая, чтобы вызвать их, вместо того, чтобы возвращать это ужасно глупое целое число -1, говорящее, что «-1 байт прочитано»). Вы говорите мне, если следующее нечитаемо / не поддерживается:

try {
    r = readNext(...);
    process(r);
} catch (EOFException e) {
    ...
}
0 голосов
/ 10 ноября 2009

Я не вижу, насколько Паттерн Стража настолько отличается, чтобы быть его собственным паттерном. Моя единственная мысль - это было бы полезно для определения значения остановки из потоковых данных. Тем не менее, интегратор позаботится об этом с помощью требования метода hasMore.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...