JavaRush /Java Blog /Random-TL /Pattern ng iterator

Pattern ng iterator

Nai-publish sa grupo
Ngayon ay pag-uusapan natin kung ano ang Iterator sa Java at kung bakit ito kinakailangan.
Pattern ng iterator - 1
Tulad ng malamang na alam mo na, ang Java ay may magandang interface ng Collection na nagpapatupad ng interface ng Iterator. Hayaan akong magpareserba kaagad: ang interface ng iterator ay hindi dapat malito sa pattern ng iterator sa Java! At para linawin, tingnan muna natin ang interface.
Sa literal, ang "Iterator" ay maaaring isalin bilang "brute force . " Iyon ay, ito ay isang tiyak na entity na maaaring umulit sa lahat ng mga elemento sa koleksyon. Bukod dito, pinapayagan ka nitong gawin ito nang hindi sinusuri ang panloob na istraktura at pag-aayos ng mga koleksyon.
Isipin natin sa isang segundo na walang iterator sa Java. Sa kasong ito, ang bawat isa ay kailangang sumisid sa kalaliman ng mga koleksyon at tunay na maunawaan kung ano ang naiiba ArrayListsa LinkedListat HashSetmula sa TreeSet.

Mga pamamaraan na dapat ipatupad ng Iterator

boolean hasNext()— kung may natitira pang value sa iterable object (kasalukuyang Collection), babalik ang method true, kung wala nang value false. E next()— ibinabalik ang susunod na elemento ng koleksyon (object). Kung wala nang mga elemento (wala nang tseke hasNext(), at tumawag kami next()kapag naabot namin ang dulo ng koleksyon), ang paraan ay magtapon NoSuchElementException. void remove()- aalisin ang elementong huling nakuha ng next(). Ang pamamaraan ay maaaring magtapon:
  • UnsupportedOperationException, kung hindi sinusuportahan ng iterator na ito ang pamamaraan remove()(sa kaso ng mga read-only na koleksyon, halimbawa)
  • IllegalStateException, kung ang pamamaraan next()ay hindi pa tinatawag, o kung ito remove()ay natawag na mula noong huling tawag next().
Kaya, ang iterator para sa Listahan ay ang pinakakaraniwang pagpapatupad. Ang iterator ay napupunta mula sa simula ng koleksyon hanggang sa katapusan nito: tinitingnan nito kung naroroon ang susunod na elemento at ibinabalik ito kung mayroon. Ang isang cycle ay binuo batay sa simpleng algorithm na ito for-each. Ang extension nito ay ListIterator. Tingnan natin ang karagdagang mga pamamaraan ng iterator ng listahan ng java. Malamang na kilala mo sila:
  • void add(E e)— naglalagay ng elemento Esa ;List
  • boolean hasPrevious()— babalik truekung Listmay mga elemento sa panahon ng reverse search;
  • int nextIndex()— ibabalik ang index ng susunod na elemento;
  • E previous()— ibabalik ang nakaraang elemento ng sheet;
  • int previousIndex()— ibabalik ang index ng nakaraang elemento;
  • void set(E e)- ay papalitan ang elementong ibinalik ng huling tawag next()o previous()ng elemento e.
Tingnan natin ang isang maliit na halimbawa. Gumawa tayo ng isang Listnaglalaman ng mga linya ng pagbati sa mga mag-aaral:
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Обучающимся");
list.add("На");
list.add("JavaRush");
Ngayon ay kukuha kami ng isang iterator para dito at i-print ang lahat ng nakapaloob na mga linya sa console:
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}
Ngayon ay magkakaroon ng "bottleneck": Mga Koleksyon ng Java, tulad ng malamang na alam mo (at kung hindi mo alam, alamin ito), pahabain ang interface Iterable, ngunit hindi ito nangangahulugan na lamang List, Setat Queuesumusuporta sa iterator. Para java Map iteratoray sinusuportahan din, ngunit dapat tawagan para sa Map.entrySet():
Map<String, Integer> map = new HashMap<>();
Iterator mapIterator = map.entrySet().iterator();
Pagkatapos ang pamamaraan next() ay magbabalik ng isang bagay Entryna naglalaman ng isang "key" - "halaga" na pares. Pagkatapos ang lahat ay pareho sa List:
while (mapIterator.hasNext()) {
    Map.Entry<String, Integer> entry = mapIterator.next();
    System.out.println("Key: " + entry.getKey());
    System.out.println("Value: " + entry.getValue());
}
Sa tingin mo: "Tumigil ka. Pinag-uusapan natin ang interface, at ang pamagat ng artikulo ay nagsasabing "Pattern". Iyon ay, ang iterator pattern ay ang Iterator interface? O ang interface ay isang pattern? Kung lumitaw ang salitang ito sa unang pagkakataon, bibigyan kita ng sanggunian: ang isang pattern ay isang pattern ng disenyo, isang tiyak na pag-uugali na dapat sundin ng isang klase o maraming magkakaugnay na mga klase. Ang isang iterator sa java ay maaaring ipatupad para sa anumang bagay na ang panloob na istraktura ay nagsasangkot ng pag-ulit, at maaari mong baguhin ang lagda ng mga pamamaraan na tinatalakay. Ang pangunahing bagay kapag nagpapatupad ng isang pattern ay ang lohika na dapat sundin ng klase. Ang interface ng iterator ay isang pribadong pagpapatupad ng pattern ng parehong pangalan, na inilapat kapwa sa mga yari na istruktura ( List, Set, Queue, Map), at sa iba pa, sa pagpapasya ng programmer. Sa pamamagitan ng pagpapalawak ng interface ng Iterator, nagpapatupad ka ng isang pattern, ngunit hindi mo kailangang pahabain ang interface upang maipatupad ang pattern. Isang simpleng pagkakatulad: lahat ng isda ay lumalangoy, ngunit hindi lahat ng lumalangoy ay isda. Bilang halimbawa, nagpasya akong kunin... ang salita. Higit na partikular, isang pangngalan. Binubuo ito ng mga bahagi: unlapi, ugat, panlapi at wakas. Para sa mga bahagi ng isang salita, gagawa kami ng interface WordPartat mga klase na magpapalawak nito: 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;
    }
}
Pagkatapos ang klase Word(salita) ay maglalaman ng mga bahagi, at bilang karagdagan sa mga ito ay magdaragdag kami ng isang integer na sumasalamin sa bilang ng mga bahagi sa salita:
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;
    }
Okay, mayroon kaming apat na overloaded na konstruktor (para sa pagiging simple, ipagpalagay natin na maaari lamang tayong magkaroon ng isang suffix). Ang isang pangngalan ay hindi maaaring binubuo ng isang prefix, kaya para sa isang constructor na may isang parameter ay itatakda namin ang ugat. Ngayon, magsulat tayo ng pagpapatupad ng pattern ng iterator: WordIterator, na nag-o-override sa 2 pamamaraan: hasNext()at 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--;
        }
    }
}
Ang natitira na lang ay italaga ang iterator sa klase Word:
public class Word implements Iterable<Word.WordPart> {@Override
	public Iterator<WordPart>iterator() {
    		return new WordIterator(this);
	}}
Ngayon ay magsagawa tayo ng morphemic analysis ng salitang "rush":
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());
        }
    }
}
Pakitandaan na sa aking pagpapatupad ng pattern ng iterator, pinili ko ang sumusunod na pagkakasunud-sunod ng output:
  1. pagtatapos
  2. panlapi
  3. console
  4. ugat
Kapag nagdidisenyo ng iyong sariling iterator, maaari mong tukuyin ang algorithm ng pag-ulit ayon sa gusto mo. Good luck sa iyong pag-aaral!
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION