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
Rakieta NASA już czeka na astronautów. Księżyc niedługo będzie miał gości
W kosmosie wybuchł "kosmiczny wulkan". Fenomenalne zjawisko!
To może być przełom w komunikacji. Teleportowali stan kwantowy między fotonami
Najważniejsze serialowe premiery 2026: na to wszyscy czekamy
Ile grania to za dużo? Naukowcy wskazują konkretną granicę
Apple Watch uratował mi zdrowie. Ta historia może być również o Tobie
Akumulatory Parkside: petarda z Lidla czy mina z opóźnionym zapłonem?
Budżetowy Xiaomi jeszcze tańszy. W takiej cenie to kradzież
Brakuje gier średnich. Ale nie w taki sposób, jak myślisz
Wkrętarka Parkside z RGB w mega promocji. Teraz 150 zł taniej
Nowe Xiaomi SU7 to pokaz technologiczny. Chiński gigant idzie na całość
Twój Samsung Galaxy S24 ma problemy z wyświetlaczem? Spokojnie, to nie usterka
Ogniwa wodorowe w 2026: gdzie „dowożą”, a gdzie wciąż nie dają rady
Disney ma dla fanów klasyków niespodziankę. Bardzo nieprzyjemną
Znaleźliśmy "chmurę żelaza" w kosmosie. Nieprawdopodobne, a jednak!
Życie bez haseł w 2026 roku. Raz to ustawiasz i logowania przestają boleć.
Komórki „nagrywają” swoje życie. Oto jak naukowcy to odkryli
Najwyższa pora na zmiany: Passkey zamiast hasła w 2026
YouTube rozluźnia zasady. Szykujcie się na zalew szamba
Festiwal nowych błędów w Windows 11 czas zacząć. To już nie jest śmieszne
To by było na tyle, jeśli chodzi o możliwość ugody
Ocalić od zapomnienia
Ostatni kwant
ALH 84001 – meteoryt, o którym mówiono nawet w Białym Domu
HESS zarejestrował kosmiczny elektron o niespotykanej energii [Phys. Rev. Lett.]
Matka ciemnej materii – recenzja biografii “Vera Rubin. Życie”
Satelita, który zerwał się ze smyczy
Wiadomość od Carla Sagana do przyszłych eksploratorów Marsa
Ile najdłużej może trwać zaćmienie Słońca?
Nowa największa liczba pierwsza ma ponad 41 milionów cyfr [GIMPS]
30 lat konsoli PlayStation – Odcinek #130
Omawiamy serię The Walking Dead (gość: Stary Gracz)
Nikt nie potrzebuje cienkich smartfonów – Odcinek #129
To ostatni dzwonek na kolekcjonowanie gier i filmów
Najlepsza relacja z PGA 2025 (Poznań Game Arena)
Bumblebee wśród klawiatur. Marvo Meqa 80W – recenzja
Pierwsze spotkanie z Omoda 7 Super Hybrid
Logitech MX Master 4, Wednesday, 1670 sezon 2 – Odcinek #128
Tani pad, który chciał być jak DualSense. Test Monka Contra GT-96
Secret Service i prasa komputerowa w Polsce – Odcinek #127

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.