JavaRush /Java блогы /Random-KK /Итератор үлгісі
Алексей Дмитревский
Деңгей
Москва

Итератор үлгісі

Топта жарияланған
Бүгін біз Java-да Итератор деген не және ол не үшін қажет екендігі туралы сөйлесеміз .
Итератор үлгісі - 1
Өздеріңіз білетіндей, Java-да Iterator интерфейсін жүзеге асыратын тамаша Collection интерфейсі бар. Маған бірден тапсырыс беруге рұқсат етіңіз: итератор интерфейсін Java тіліндегі итератор үлгісімен шатастырмау керек! Түсіндіру үшін алдымен интерфейсті қарастырайық.
Сөзбе-сөз «Итератор» сөзін «дөрекі күш » деп аударуға болады . Яғни, бұл жинақтағы барлық элементтерді қайталай алатын белгілі бір нысан. Сонымен қатар, бұл коллекциялардың ішкі құрылымы мен орналасуын зерттемей-ақ жасауға мүмкіндік береді.
Бір секундқа Java-да итератор жоқ деп елестетіп көрейік. Бұл жағдайда әрқайсысы жинақтардың тереңдігіне сүңгуі керек және одан не айырмашылығы бар екенін шынымен ArrayListтүсінуі LinkedListкерек . HashSetTreeSet

Итератор енгізуі керек әдістер

boolean hasNext()— егер қайталанатын нысанда әлі де мәндер болса (қазіргі Жинақ), trueартық мәндер болмаса, әдіс қайтарылады false. E next()— коллекцияның келесі элементін (нысанын) қайтарады. Егер басқа элементтер болмаса (чек болған жоқ және біз жинақтың соңына жеткенде hasNext()шақырдық ), әдіс тастайды . - соңғы рет алынған элементті жояды . Әдіс тастай алады: next()NoSuchElementExceptionvoid remove()next()
  • UnsupportedOperationException, егер бұл итератор әдіске қолдау көрсетпесе remove()(мысалы, тек оқуға арналған жинақтар жағдайында)
  • IllegalStateException, егер әдіс next()әлі шақырылмаған болса немесе ол remove()соңғы қоңыраудан бері шақырылған болса next().
Сонымен, List үшін итератор ең көп тараған іске асыру болып табылады. Итератор жинақтың басынан аяғына дейін жүреді: ол келесі элементтің бар-жоғын тексереді және егер бар болса, оны қайтарады. Осы қарапайым алгоритм негізінде цикл құрылады for-each. Оның кеңейтімі - ListIterator. Қосымша java тізімінің итератор әдістерін қарастырайық. Сіз оларды білуіңіз мүмкін:
  • void add(E e)— элементті Eішіне енгізеді ;List
  • boolean hasPrevious()— кері іздеу кезінде элементтер болса trueқайтарады ;List
  • int nextIndex()— келесі элементтің индексін қайтарады;
  • E previous()— алдыңғы парақ элементін қайтарады;
  • int previousIndex()— алдыңғы элементтің индексін қайтарады;
  • void set(E e)next()- соңғы қоңырау арқылы қайтарылған элементті немесе previous()элементті ауыстырады e.
Шағын мысалды қарастырайық. ListОқушыларға сәлемдесу жолын құрайық :
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Обучающимся");
list.add("На");
list.add("JavaRush");
Енді біз оған итератор аламыз және консольге барлық жолдарды басып шығарамыз:
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}
Енді «тарыл» болады: Java жинақтары, сіз білетіндей (және егер сіз білмесеңіз, оны анықтаңыз), интерфейсті кеңейтіңіз , бірақ бұл тек итераторды қолдайтынын білдірмейді Iterable. For- ға да қолдау көрсетіледі, бірақ мыналар үшін шақырылуы керек : ListSetQueuejava Map iteratorMap.entrySet()
Map<String, Integer> map = new HashMap<>();
Iterator mapIterator = map.entrySet().iterator();
Содан кейін әдіс «кілт» - «мән» жұбы бар next() нысанды қайтарады . EntryСонда бәрі бірдей List:
while (mapIterator.hasNext()) {
    Map.Entry<String, Integer> entry = mapIterator.next();
    System.out.println("Key: " + entry.getKey());
    System.out.println("Value: " + entry.getValue());
}
Сіз ойлайсыз: «Тоқта. Біз интерфейс туралы айтып отырмыз, ал мақаланың тақырыбы «Үлгі» деп аталады. Яғни, итератор үлгісі Итератор интерфейсі болып табылады ма? Немесе интерфейс үлгі ме? Егер бұл сөз бірінші рет пайда болса, мен сізге анықтама беремін: үлгі - дизайн үлгісі, сынып немесе көптеген өзара байланысты сыныптар ұстануға тиіс белгілі бір мінез-құлық. Java тіліндегі итератор ішкі құрылымы қайталануды қамтитын кез келген нысан үшін жүзеге асырылуы мүмкін және талқыланатын әдістердің қолтаңбасын өзгертуге болады. Үлгіні жүзеге асыру кезінде ең бастысы - сынып ұстанатын логика. Итератор интерфейсіList, Set, Queue, Map - бұл бағдарламашының қалауы бойынша дайын құрылымдарға да ( ) және басқаларға да қолданылатын аттас үлгінің жеке жүзеге асырылуы . Итератор интерфейсін кеңейту арқылы сіз үлгіні орындайсыз, бірақ үлгіні енгізу үшін интерфейсті кеңейтудің қажеті жоқ. Қарапайым ұқсастық: барлық балықтар жүзеді, бірақ жүзетіндердің бәрі балық емес. Мысал ретінде... сөзін алуды жөн көрдім. Нақтырақ айтқанда, зат есім. Ол бөліктерден тұрады: префикс, түбір, жұрнақ және аяқталу. WordPartСөз бөліктері үшін интерфейсті және оны кеңейтетін сыныптарды жасаймыз : Prefix, Root, Suffix и Ending:
interface WordPart {
    String getWordPart();
}

static class Root implements WordPart {

    private String part;

    public Root(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}

static class Prefix implements WordPart {

    private String part;

    public Prefix(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}

static class Suffix implements WordPart {

    private String part;

    public Suffix(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}

static class Ending implements WordPart {

    private String part;

    public Ending(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}
Содан кейін сыныпта Word(сөзде) бөліктер болады және оларға қосымша сөздегі бөліктердің санын көрсететін бүтін санды қосамыз:
public class Word {

    private Root root;
    private Prefix prefix;
    private Suffix suffix;
    private Ending ending;
    private int partCount;

    public Word(Root root, Prefix prefix, Suffix suffix, Ending ending) {
        this.root = root;
        this.prefix = prefix;
        this.suffix = suffix;
        this.ending = ending;
        this.partCount = 4;
    }

    public Word(Root root, Prefix prefix, Suffix suffix) {
        this.root = root;
        this.prefix = prefix;
        this.suffix = suffix;
        this.partCount = 3;

    }

    public Word(Root root, Prefix prefix) {
        this.root = root;
        this.prefix = prefix;
        this.partCount = 2;
    }

    public Word(Root root) {
        this.root = root;
        this.partCount = 1;
    }

    public Root getRoot() {
        return root;
    }

    public Prefix getPrefix() {
        return prefix;
    }

    public Suffix getSuffix() {
        return suffix;
    }

    public Ending getEnding() {
        return ending;
    }

    public int getPartCount() {
        return partCount;
    }

    public boolean hasRoot() {
        return this.root != null;
    }

    public boolean hasPrefix() {
        return this.prefix != null;
    }

    public boolean hasSuffix() {
        return this.suffix != null;
    }

    public boolean hasEnding() {
        return this.ending != null;
    }
Жарайды, бізде шамадан тыс жүктелген төрт конструктор бар (қарапайымдылық үшін бізде тек бір жұрнақ болуы мүмкін делік). Зат есім бір префикстен тұруы мүмкін емес, сондықтан бір параметрі бар конструктор үшін біз түбірді орнатамыз. Енді итератор үлгісінің іске асырылуын жазайық: WordIterator, 2 әдісті қайта анықтау: hasNext()және next():
public class WordIterator implements Iterator<Word.WordPart> {

    private Word word;
    private int wordPartsCount;

    public WordIterator(Word word) {
        this.word = word;
        this.wordPartsCount = word.getPartCount();
    }

    @Override
    public boolean hasNext() {
        if (wordPartsCount == 4) {
            return word.hasPrefix() || word.hasRoot() || word.hasSuffix() || word.hasEnding();
        } else if (wordPartsCount == 3) {
            return word.hasPrefix() || word.hasRoot() || word.hasSuffix();
        } else if (wordPartsCount == 2) {
            return word.hasPrefix() || word.hasRoot();
        } else if (wordPartsCount == 1) {
            return word.hasRoot();
        }
        return false;
    }

    @Override
    public Word.WordPart next() throws NoSuchElementException {
        if (wordPartsCount <= 0) {
            throw new NoSuchElementException("No more elements in this word!");
        }

        try {
            if (wordPartsCount == 4) {
                return word.getEnding();
            }
            if (wordPartsCount == 3) {
                return word.getSuffix();
            }
            if (wordPartsCount == 2) {
                return word.getPrefix();
            }
            return word.getRoot();
        } finally {
            wordPartsCount--;
        }
    }
}
Итераторды сыныпқа тағайындау ғана қалады Word:
public class Word implements Iterable<Word.WordPart> {@Override
	public Iterator<WordPart>iterator() {
    		return new WordIterator(this);
	}}
Енді «асығыс» сөзіне морфемиялық талдау жасайық:
public class Main {
    public static void main(String[] args) {
        Word.Root root = new Word.Root("беж");
        Word.Prefix prefix = new Word.Prefix("пере");
        Word.Suffix suffix = new Word.Suffix("к");
        Word.Ending ending = new Word.Ending("a");

        Word word = new Word(root, prefix, suffix, ending);

        Iterator wordIterator = word.iterator();
        while (wordIterator.hasNext()) {
            Word.WordPart part = (Word.WordPart) wordIterator.next();
            System.out.println(part.getClass() + ": " + part.getWordPart());
        }
    }
}
Итератор үлгісін іске асыруда келесі шығару тәртібін таңдағанымды ескеріңіз:
  1. аяқталады
  2. жұрнақ
  3. консоль
  4. тамыр
Өзіңіздің итераторыңызды құрастырған кезде итерация алгоритмін қалауыңызша көрсетуге болады. Оқуларыңызға сәттілік!
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION