Skip to content

Witaj w Świecie Jutra!

  • Technologie jutra
  • Sprzęt jutra
  • Aplikacje jutra
  • Programowanie
  • Księga Drogi
  • Renowacja
  • Różności
  • Archiwum
  • Autor
  • Home
  • Wszystko
  • Wzorce projektowe – Iterator
  • Programowanie
  • Wszystko

Wzorce projektowe – Iterator

Jakub Raczkowski 27 stycznia 2024

Żrodło: film Terminator 2

Wzorzec, który dzisiaj omawiamy jest chyba najbardziej przydatny ze wszystkich, które do tej pory przerobiliśmy. To na nim właśnie stoi cała biblioteka Java Collections. Wzorzec Iterator jest tak niezbędny, że… aż niepotrzebny.

W artykule „SOLIDne programowanie” omawialiśmy najważniejsze zasady, które powinny przyświecać nam w czasie gdy piszemy kod. Każda z liter słowa SOLID nawiązywała do innej reguły. Tym razem skupimy się na „D” od Dependency Inversion.

Zasada odwrócenia zależności mówi nam abyśmy unikali tworzenia sztywnych połączeń opartych na konkretnych klasach:

class Example{}

class Main{
	void exampleMethod(Example example){
	(...)
	}
} 

Jeśli zrobimy to jak powyżej i nasza przykładowa metoda (exampleMethod) będzie działać tylko z tą jedną klasą Example, to sami sobie tworzymy kłopoty na przyszłość. Lepiej oprzeć parametr na abstrakcji:

interface Example{}

class Main{
	void exampleMethod(Example example){
	(...)
	}

Zmiana mała, za to efekt ogromny – teraz klasa nie boi się rozwoju, a ponadto metoda exampleMethod nie wie nic o obiekcie który do niej trafi, czyli jednocześnie zachowujemy wysoką hermetyzację.

Wzorzec Iterator jest odpowiedzią właśnie na te dwie potrzeby:

  • chcemy uzależnić metodę od abstrakcji zamiast od konkretnej klasy
  • chcemy hermetyzować elementy, które mogą ulec zmianie w przyszłości

Wzorzec Iterator zapewnia metodę dostępu sekwencyjnego do elementów obiektu zagregowanego bez ujawniania jego reprezentacji wewnętrznej.

Rusz głową! Wzorce projektowe
Lepszego obrazka nie udało mi się znaleźć 😉 Źródło: film American Pie

We wstępniaku napisałem, że Iterator jest jednocześnie niezbędny i zbędny. Chodzi o to, że tak świetnie uzupełnia kolekcje, że już dawno temu został włączony do pakietu java.util, a każda klasa implementująca interfejs Collections (listy, mapy, kolejki, stosy) musi mieć metodę getIterator() która automatycznie generuje nam iterator danej kolekcji.

W związku z powyższym omawianie tego wzorca tutaj jest po trochu zbędne – szansa na to, że będziemy musieli kiedykolwiek napisać własny iterator zamiast na szybko skorzystać z gotowej metody są niewielkie.

Jednakowoż może się to zdarzyć, gdy będziemy pracować ze zwykłymi tablicami, które takiej metody nie posiadają.

Ale po kolei…

Tym razem znów nawiążemy do gier Diablopodobnych zamiast klasycznych cRPG. Wszystkie te clickery mają to do siebie, że oręż generowany jest losowo – randomizowane są statystyki, nazwy, czasem nawet wygląd. Jednocześnie mamy w grze elementy, które są stałe i za każdym razem dokładnie takie same – jak na przykład mikstury: „uleczajki„.

Ekwipunek przed walką z bossem. Diablo 1

Mamy małą uleczajkę, która przywraca 20% maksymalnych punktów zdrowia, średnią dającą 50% i dużą, która zawsze regeneruje do pełna. To samo z miksturami przywracającymi manę, niezbędną do rzucania zaklęć. Razem dokładnie 6 pozycji.

Jeśli chciałbym to zakodować (pełna wersja tutaj) i zrobić listę gotową do zaprezentowania w sklepie z potionami to z pewnością użyłbym zwykłej tabeli, która działa szybciej od list czy setów, a ponadto zużywa mniej pamięci.

String[] elixirs = new String[6];
        public ElixirStore() {
            elixirs[0] = "Mała mikstura regeneracji zdrowia";
            elixirs[1] = "Średnia mikstura regeneracji zdrowia";
            elixirs[2] = "Duża mikstura regeneracji zdrowia";
            elixirs[3] = "Mała mikstura regeneracji many";
            elixirs[4] = "Średnia mikstura regeneracji many";
            elixirs[5] = "Duża mikstura regeneracji many";
        }

Natomiast, gdybym to samo chciał zrobić z losowo generowanym orężem to lepiej byłoby mi skorzystać choćby z ArrayList, która automatycznie się powiększa – zmieści i milion pozycji:

List<String> weapons = new ArrayList<>();

        public WeaponShop() {
            for (int i = 0; i < 10; i++) {
                generateAndAddWeapon();
            }
        }

Póki co wszystko działa jak należy, problem może pojawić się gdy będziemy chcieli połączyć oba sklepy: z bronią i z miksturami. Wtedy takie centrum handlowe musiałoby mieć dwie osobne pętle:

for (String elixir : elixirStore.elixirs) {
            System.out.println(elixir);
        }

for (String weapon : weaponShop.weapons) {
            System.out.println(weapon);
        }

Na chwilę obecną nie wydaje się to krytyczną sytuacją, ale z każdym kolejnym sklepem (ze zbroją, z biżuterią, z czarami, z płaszczami, z tatuażami…) pętli będzie przybywać, a kod się będzie komplikował i zaciemniał.

Dlatego już teraz warto przemyśleć strukturę i dodać iteratory. Ten ze sklepu z bronią dostaniemy automatycznie, metodą z kolekcji:

Iterator<String> getIterator(){
            return weapons.iterator();
        }

Ale ten z tablicy z miksturami będziemy musieli stworzyć samodzielnie:

Własnoręcznie stworzony Iterator do naszej tabeli.

Wbrew pozorom nie jest to nic szczególnie skomplikowanego – ot tworzymy nową klasę, która implementuje javowy interfejs Iterator. To zmusza nas do dodania co najmniej dwóch metod: hasNext() oraz next(), które musimy zaimplementować samodzielnie. Możemy też opcjonalnie dodać funkcję remove() usuwającą element kolekcji.

I gotowe. Nasz uniwersalny sklep działa i oferuje to co trzeba. A wszystko realizujemy jedną linijką kodu, która przyjmie tyle iteratorów ile chcemy.

new GeneralStore(elixirStore.getIterator(), weaponShop.getIterator()).printOffer();
Nasze centrum handlowe już działa!

ITCandidateEvaluator

Tak jak pisałem wcześniej – własna implementacja wzorca Iterator wydaje mi się całkowicie zbędna z obecnego punktu widzenia. Nie potrafię sobie również wyobrazić sytuacji, że będę tego potrzebował w przyszłości.

Co więcej, wraz z wprowadzeniem strumieni w Java 8 iteratory straciły trochę na znaczeniu. Teraz zamiast lecieć po kolejnych elementach listy, lepiej utworzyć strumień, ustawić filtry i zebrać to na czym nam zależy.

A mi (poza oczywiście ukończeniem projektu) zależy na przećwiczeniu tychże strumieni (i lambd) z którymi wciąż miałem niewystarczający kontakt. Fajnie było się dowiedzieć na jakiej zasadzie działają iteratory, ale zostawmy tę wiedzę w szufladce otagowanej nalepką „może kiedyś” i zajmijmy się czymś ciekawszym.

Być może taki okaże się Kompozyt (Composite), którym zajmiemy się już w następnym artykule.

Tags: design patterns programming

Continue Reading

Previous: Wzorce projektowe – Template Method
Next: Wzorce projektowe – Composite

Related Stories

Mageege Moon104 – test niskoprofilowego mechanika
  • Sprzęt

Mageege Moon104 – test niskoprofilowego mechanika

11 marca 2025
Przebranżowienie cz.4
  • Programowanie

Przebranżowienie cz.4

27 lutego 2025
Smartfon Jutra
  • Sprzęt

Smartfon Jutra

15 lutego 2025

Ze świata

  • Antyweb
  • Kwantowo
  • Dwóch po dwóch
GTA VI to wisienka na torcie. Jesień na Xbox to wysyp innych hitów
Głośnik jak karton mleka. Takiej nietuzinkowej technologii nam trzeba
Prawdziwy wysyp hitów na PS5. Ta jesień przejdzie do historii
Przyspiesz Windows 11 bez pobierania żadnych apek
Użytkownicy Windowsa popełniają duży błąd. Ekspert tłumaczy zły nawyk
PKO BP odcina klientów od aplikacji. I to w środku tygodnia
Twój telewizor jest za jasny. Oto dlaczego powinieneś to naprawić
Nikt nie chce kupować komputerów. Ostatni kwartał był katasfrofą
Jak zeskanować kod QR na własnym ekranie telefonu — bez drugiego urządzenia
Pomidory na Księżycu? A to tylko początek
Apple TV nie zwalnia tempa. Te seriale zobaczymy jeszcze tej jesieni
Nowa opaska Google ma coś, czego brakuje wielu smartwatchom. Premiera tuż tuż
Kupujesz akumulator Parkside? Na te oznaczenia trzeba uważać
Internet dla studenta. Znalazłem najlepszy pakiet
Nowa funkcja w Mapach Google. Pokaże same hity
Pierwszy składak Apple w Plusie. Jest drogo...
Prościej, wygodniej i szybciej. Tak teraz pracuję na komputerze
ChatGPT wpadł w pułapkę? Jest kłopot z rozwiązaniem problemu Naviera-Stokesa
Za co naprawdę płacimy, kupując słuchawki premium? Wyjaśniamy na przykładzie Bowers & Wilkins Px7 S3
Recenzja Forever Ago. Piękna opowieść z nudną rozgrywką
O powstawaniu kamieni drogą doboru naturalnego
Świat upomina się o „właściwe” proporcje
Kosmiczna panorama i superkoronograf – co przyniesie nam Teleskop Nancy Roman?
O czym szepczą między sobą bozony Higgsa?
Wszechświat w trzech aktach – recenzja książki “Astronomia, kosmologia i astronautyka”
Wielka przerwa Wielkiego Zderzacza
A gdyby tak przeciąć foton na pół?
SpudCell – syntetyczna komórka, która udaje życie
Mega upał, omega manipulacja
Coraz więcej dowodów, coraz mniej pewności
Wyglądają i grają jak premium, a kosztują ułamek tej ceny. Recenzja Baseus Inspire XH1
WRZESIEŃ BĘDZIE MOCNY… Premiery gier, na które czekamy – Mamy do pogrania
Całkiem dobry film ten nowy Spider-Man: Brand New Day 🕷️ – No Movie Ci #18
Scyzorykon 2026, Galaxy Fold8 i całkiem nowy Spider-Man – Odcinek #137
Sprawdziliśmy Scyzorykon 2026 od środka!
Co się działo na Fantasy & Magic Con w Warszawie?
Porozmawiajmy o Steam Machine 🎮👀
Przedsprzedaż GTA VI, Stargate i gry, które paliły sprzęty – Odcinek #136
Relacja z CD-Action Expo 2026
Tańszy Game Pass, droższy Steam Deck i Internet 0202122 – Odcinek #135

To może cię zainteresować:

Mageege Moon104 – test niskoprofilowego mechanika
  • Sprzęt

Mageege Moon104 – test niskoprofilowego mechanika

11 marca 2025
Przebranżowienie cz.4
  • Programowanie

Przebranżowienie cz.4

27 lutego 2025
Smartfon Jutra
  • Sprzęt

Smartfon Jutra

15 lutego 2025
Czym jest Swagger?
  • Programowanie

Czym jest Swagger?

22 lipca 2024
  • Technologie jutra
  • Sprzęt jutra
  • Aplikacje jutra
  • Programowanie
  • Księga Drogi
  • Renowacja
  • Różności
  • Archiwum
  • Autor
Copyright © All rights reserved. | DarkNews by AF themes.