Более продвинутое использование интерфейсов - PullRequest
0 голосов
/ 12 апреля 2010

Если честно, я не совсем уверен, что понимаю задачу сам :) Мне сказали создать класс MySimpleIt, который реализует Iterator и Iterable и позволит запустить предоставленный тестовый код. Аргументы и переменные объектов не могут быть ни коллекциями, ни массивами.
Код:

 MySimpleIt msi=new MySimple(10,100,
                           MySimpleIt.PRIME_NUMBERS);

 for(int el: msi)
   System.out.print(el+" ");    
 System.out.println();

 msi.setType(MySimpleIterator.ODD_NUMBERS);
 msi.setLimits(15,30);
 for(int el: msi)
   System.out.print(el+" ");    
 System.out.println();

 msi.setType(MySimpleIterator.EVEN_NUMBERS);
 for(int el: msi)
   System.out.print(el+" ");    
 System.out.println();

Результат, который я должен получить:

11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 


15 17 19 21 23 25 27 29 


16 18 20 22 24 26 28 30

А вот и мой код:

import java.util.Iterator; 
interface MySimpleIterator{
    static int ODD_NUMBERS=0;
    static int EVEN_NUMBERS = 1;
    static int PRIME_NUMBERS = 2;

    int setType(int i);
}

public class MySimpleIt implements Iterable, Iterator, MySimpleIterator {    
    public MySimple my;

    public MySimpleIt(MySimple m){ 
        my = m;      
    }

    public int setType(int i){
        my.numbers = i;
        return my.numbers;
    }

    public void setLimits(int d, int u){
        my.down = d;
        my.up = u;
    }

    public Iterator iterator(){
        Iterator it = this.iterator();
        return it;
    }

    public void remove(){  
    }

    public Object next(){
        Object o = new Object();
        return o;
    }

    public boolean hasNext(){
        return true;
    }

}

class MySimple {
    public int down;
    public int up;
    public int numbers;

    public MySimple(int d, int u, int n){
        down = d;
        up = u;
        numbers = n;
    }
}

В тестовом коде у меня ошибка в строке при создании объекта MySimpleIt msi, так как он находит MySimple вместо MySimpleIt. Также у меня есть ошибки в циклах for-each, потому что компилятор хочет, чтобы там были int-ы вместо Object У кого-нибудь есть идеи о том, как ее решить?

1 Ответ

6 голосов
/ 12 апреля 2010

Есть много неправильных в дизайне этого задания.

Использование enum

Тестовый код содержит следующие фрагменты:

MySimpleIt(erator?).PRIME_NUMBERS
MySimpleIt(erator?).ODD_NUMBERS
MySimpleIt(erator?).EVEN_NUMBERS

В одном месте тип MySimpleIt, в другом - MySimpleIterator. В любом случае, имя предлагает использовать интерфейс для определения группы констант. ЭТО НЕ ПРАВИЛЬНОЕ ИСПОЛЬЗОВАНИЕ interface !!!

Было бы гораздо лучше использовать enum вместо:

enum SequenceType {
  PRIME_NUMBERS, ODD_NUMBERS, EVEN_NUMBERS;
}

См .: Effective Java 2nd Edition Элемент 30: Использовать перечисления вместо int констант.


Рассмотрим несколько реализаций interface вместо монолита с setType

Похоже, ваш секвенсор должен иметь возможность переключать тип последовательности по прихоти. Это приведет к тому, что этот класс будет огромным BLOB-объектом, который должен знать, как генерировать последовательности каждого типа. Это может хорошо работать только для 3 типов, приведенных здесь, но это определенно плохой дизайн, если позже вы захотите добавить больше типов последовательностей.

Рассмотрим просто наличие разных реализаций одного и того же интерфейса для разных типов последовательностей. Возможно, вы захотите определить AbstractIntegerSequencer, который определяет базовую функциональность (сброс границ, ответ hasNext(), iterator() и т. Д.), Который делегирует abstract protected int generateNext() для подклассов @Override. Таким образом, специфика типа генерируемой последовательности красиво инкапсулируется в каждом подклассе.

Вы все еще можете оставить enum SequenceType для фабричного метода static, который создает эти разные подклассы, по одному для каждого типа последовательности, но сами эти последовательности, вероятно, не смогут переключать тип по прихоти.


Используйте дженерики

Вместо того, чтобы делать ваш тип implements Iterator, вы должны сделать его implements Iterator<Integer>.

С JLS 4.8 Типы сырья (выделение их):

Использование необработанных типов разрешено только в качестве уступки совместимости устаревшего кода. Использование необработанных типов в коде, написанном после введения универсальности в язык программирования Java, настоятельно не рекомендуется. Возможно, что будущие версии языка программирования Java будут запрещать использование необработанных типов .

См. Также Effective Java 2nd Edition Элемент 32: Не используйте необработанный тип в новом коде.


Не путайте Iterator<T> с Iterable<T>.

Допустим, у вас есть что-то вроде этого:

IntegerSequencer seq = new PrimeSequencer(0, 10);

for (int i : seq) {
  System.out.println(i);
} // prints "2", "3", "5", 7"

for (int i : seq) {
  System.out.println(i);
} // what should it print???

Если вы сделаете seq implements Iterable<Integer>, Iterator<Integer> и @Override Iterator<Integer> iterator() до return this;, то второй цикл не будет ничего печатать, так как seq является его собственным iterator(), и на этом этапе больше нет hasNext() для seq.

Правильная реализация Iterable<Integer> должна быть способна генерировать столько независимых Iterator<Integer>, сколько необходимо пользователю, и такая реализация снова будет печатать простые числа между 0 и 10 в приведенном выше коде.


Дальнейшие чтения по стеку

...