Решаю задачку. Наколбасил кода. И в один прекрасный момент немного засутпорился. Есть метод
Он чудный :) но не об этом сейчас. Нужно очень быстро сделать так, чтобы в зависимости от boolean direction параметра метод итерировался по второму циклу (int x) в прямом, либо в обратном порядке (но в том же диапазоне).
Копипаст и if с двумя циклами не катит - дублирование. Выделить внутренности цикла int x тоже не катит - много зависимостей. Да и не интересно - я так уже делал в молодости :)
Некрасивый код стал еще более некрасивым.
Как быть? И тут приходит идея. А что если поспользоваться интерфейсом Iterable? По нему for ходит без пороблем. Выглядеть это будет приблизительно так.
А вот и сам класец. Только внимание, я его сделал таким, что о сам определяет где from где to даже если ты их перепутал местами - то немного неочевидно, фор не работает так, но мне удобно!
Он чудный :) но не об этом сейчас. Нужно очень быстро сделать так, чтобы в зависимости от boolean direction параметра метод итерировался по второму циклу (int x) в прямом, либо в обратном порядке (но в том же диапазоне).
Копипаст и if с двумя циклами не катит - дублирование. Выделить внутренности цикла int x тоже не катит - много зависимостей. Да и не интересно - я так уже делал в молодости :)
Как быть? И тут приходит идея. А что если поспользоваться интерфейсом Iterable? По нему for ходит без пороблем. Выглядеть это будет приблизительно так.
public class XIterator implements Iterable<Integer>{
private int from;
private int to;
private int x;
private boolean increase;
public XIterator(int from, int to, boolean increase) {
if (increase) {
this.from = Math.min(from, to);
this.to = Math.max(from, to);
} else {
this.from = Math.max(from, to);
this.to = Math.min(from, to);
}
this.increase = increase;
this.x = this.from;
}
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
@Override
public boolean hasNext() {
if (increase) {
return x <= to;
} else {
return x >= to;
}
}
@Override
public Integer next() {
if (increase) {
return x++;
} else {
return x--;
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
Вот тесты для него
public class XIteratorTest {
@Test
public void increase() {
assertIteratorValues(new XIterator(0, 10, true), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]");
}
@Test
public void decrease() {
assertIteratorValues(new XIterator(0, 10, false), "[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]");
}
@Test
public void increaseNegative() {
assertIteratorValues(new XIterator(-5, 5, true), "[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]");
}
private void assertIteratorValues(Iterable<Integer> iterator, String expected) {
LinkedList list = new LinkedList();
for (Integer i : iterator) {
list.add(i);
}
assertEquals(expected, list.toString());
}
@Test
public void decreaseNegative() {
assertIteratorValues(new XIterator(-5, 5, false), "[5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5]");
}
@Test
public void increaseBadFromTo() {
assertIteratorValues(new XIterator(5, -5, true), "[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]");
}
@Test
public void decreaseBadFromTo() {
assertIteratorValues(new XIterator(5, -5, false), "[5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5]");
}
@Test
public void zeroIterator() {
assertIteratorValues(new XIterator(0, 0, false), "[0]");
assertIteratorValues(new XIterator(0, 0, true), "[0]");
}
}




Да... тяжело же в жабе без linq. Печаль:(
ОтветитьУдалитьНе то слово :)
ОтветитьУдалитьСаша, а я не считаю вызов метода в двух местах дублированием кода. То, что ты с нуля написал итератор, является большим злом, как по мне.
ОтветитьУдалитьПосчитай сам: кол-во потенциальных ошибок и проблем при "дублировании" вызовов метода и написании нового велосипеда вообще не сравнимо.
Кстати, у апача есть реверсный итератор: http://commons.apache.org/collections/api-release/org/apache/commons/collections/iterators/ReverseListIterator.html
Велосипеды писать стоит. На них учишься. Не поймешь как оно работает, пока сам не разберешь и не соберешь обратно. Эксперименты, вот чего не стоит бояться. Ошибки делать.
ОтветитьУдалитьКстати, студенты наши реализовывают List'ы, Queue вкачестве домашки - откуда у них это желание, как думаешь? :)
Вообще, как это говорится - сделай это рабочим, сделай это красивым и сделай это быстрым. http://c2.com/cgi/wiki?MakeItWorkMakeItRightMakeItFast
После того, как написал велосипед стоит найти кого-то, кто это сделал уже давно - у него код оптимальнее и сделать замену реализации.
А вообще этот код я даже обсуждать бы не стал, я вчера на него смотрел и он казался ужасным, а сегодня вообще молчу.
Но идея с экстрактом for'a в контексте еще одного типа реаткоринга я заценил. Потому тут образовался этот пост. Уверен, когда-нибудь этот тип рефакторинга будет очень к месту. Люблю их экспериментировать.