Prawie jak lambda, w Javie

2011-06-02 20:52

Wiadomo powszechnie, że Java listenerami stoi i typowe jest używanie jest różnego rodzaju klas wewnętrznych, które są następnie podawane jako interfejsy do wywołań zwrotnych. W ten sposób obsługuje się różnego rodzaju zdarzenia, począwszy od interakcji użytkownika z programem aż po ważne notyfikacje pochodzące z systemu operacyjnego.
Gdy klasa zawierające takie handlery dostatecznie się rozrośnie, pojawia się oczywiście potrzeba jej zrefaktorowania i podzielenia na dwie lub większą liczbę mniejszych. W trakcie tego procesu czasami chciałoby się też wydzielić owe klasy wewnętrzne, obsługujące zdarzenia – i wtedy możemy napotkać pewien kłopot. Kłopocik właściwie ;)

Dotyczy on zależności między klasami wewnętrznymi a klasą je otaczającą. Ponieważ mówimy o niestatycznych niestatycznych klasach wewnętrznych, typowe jest odwoływanie się do składników klasy otaczającej z klasy zewnętrznej. Mówiąc bardziej po ludzku, implementacja np. zdarzenia kliknięcia przycisku może sięgać do obiektu okna/dialogu/itp., zawierającego tenże przycisk:

  1. private final OnClickListener buttonsListener = new View.OnClickListener() {
  2.     @Override
  3.     public void onClick(View v) {
  4.         if (v.getId() == R.id.exit_button) finish();
  5.     }
  6. }

Przeniesienie całej powyższej klasy w inne miejsce nastręcza wówczas problem, gdyż odwołuje się ona do metody klasy ją otaczającej (czyli finish()). Należałoby więc posiadać obiekt tej klasy, zapewnić aby rzeczona metoda była dostępna (co nie zawsze jest wskazane), aby wywoływać ją z właściwymi parametrami – które też trzeba jakoś przekazać – i tak dalej… Krótko mówiąc na naszej drodze do ładnie zorganizowanego kodu naraz pojawia się sporo przeszkód.

Czy nie dałoby się po prostu jakoś przekazać tego “kawałka kodu”, tych kilku czy kilkunastu instrukcji opakowanych w coś, co można podać w inne miejsce programu?… Okazuje się, że jak najbardziej, a rozwiązaniem na problem refaktorowanych klas wewnętrznych jest… więcej klas wewnętrznych ;-) Nic nie stoi bowiem na przeszkodzie, aby rzeczony fragment procedury zdarzeniowej zapakować w metodę klasy implementującej interfejs Runnable. Tak, dokładnie ten interfejs który zazwyczaj kojarzy się z wątkami i klasą Thread. W rzeczywistości reprezentuje on “cokolwiek co da się uruchomić”, więc jak ulał pasuje w charakterze rozwiązania problemu.
Aplikując je do powyższego przykładu, możemy wydzielić powyższy listener (potencjalnie wraz z kilkunastoma podobnymi) i kazać mu jedynie wywoływać metodę run jakiegoś obiektu Runnable. W niej zaś umieszczamy nasz pierwotny kod i przekazujemy do nowo wydzielonej klasy:

  1. Buttons.setExitAction(new Runnable() {
  2.     @Override
  3.     public void run() { finish(); }
  4. }

Znawcy tematu powiedzieliby, że w ten sposób utworzyliśmy domknięcie (closure), bo w inne miejsce programu przekazaliśmy fragment kodu wraz z jego kontekstem; w tym przypadku jest to chociażby referencja this na rzecz której wywoływany jest finish. Fani programowania funkcyjnego stwierdzą z kolei, że ta technika jest kiepską imitacją wyrażeń lambda i najprawdopodobniej też będą mieli rację.
Nie zmienia to jednak faktu, że jeśli programujemy w starej (nie)dobrej Javie, to technika ta może być po prostu użyteczna – niezależnie od tego, jaki paradygmat za nią stoi. Dlatego też chciałem dzisiaj się nią podzielić.

Be Sociable, Share!
Be Sociable, Share!
Tags: , , , ,
Author: Xion, posted under Programming »


9 comments for post “Prawie jak lambda, w Javie”.
  1. zwierzak:
    June 2nd, 2011 o 20:32

    To co nazywasz imitacją wyrażeń ma swoją nazwę: klasy anonimowe.

    Właśnie z ich powodu Sun stwierdził, że nie ma sensu do Javy wprowadzać wyrażeń lambda, bo zastępują one je w 100%.

  2. Janusz Pawlak:
    June 3rd, 2011 o 18:26

    moim zdaniem obecnie programowanie dąży do tego aby powodować coraz większe wykluczenie cyfrowe społeczeństwa. Nie może być tak że aby napisać jakiś prosty program trzeba spędzić całe dni na naukę, to powinno być tak zrobione że pare komend i jest przykładowo kalkulator, pare innych komend i jest już coś jak word, troche więcej komend i mamy już gre a nie tak jak teraz jest gdzie do stworzenia okienka potrzeba conajmniej 20-30 linii kodu które NIC nie mówią dla przeciętnego człowieka.
    Zresztą pisałem już do kilku europosłów w tej sprawie (ponieważ jest to dyskryminacja uczciwego człowieka) ale odpowiedzi nie dostałem.

  3. goodAdviceUncle:
    June 3rd, 2011 o 19:42

    @Janusz Pawlak:
    Reguła kiss mówiąc krótko … trudno sie nie zgodzić …

  4. olo16:
    June 4th, 2011 o 8:13

    @Janusz Pawlak: Zaraz, że co? Czy ty w ogóle umiesz programować, czy jesteś tym “przeciętnym człowiekiem”? Bo jakbyś umiał to chyba byś nie pisał takich bzdur. Napisz do europosłów, że oprócz programowania dyskryminuje cię również elektronika (bo nie możesz ot tak bez żadnej wiedzy stworzyć własnego procesora – chamstwo, jak tak można!), biologia (dlaczego my zwykli obywatele nie mamy bawić się w GMO?), matematyka (ja jestem geniuszem, stworzyłem nową matematykę (nowa matematyka – czytaj: nie umiem nawet poprawnie dodawać)) i wszystkie inne nauki.

    Obraź się na wszystkie nauki, bo bez zaawansowanej wiedzy nie możesz w nich nic zrobić. Albo napisz własny język programowania, w którym grę napiszesz w kilku komendach więcej niż word, którego to napiszesz w kilku komendach więcej niż prosty kalkulator.

    Dyskryminacja uczciwego człowieka – o czym ty mówisz? Co ma tutaj uczciwość? Ach tak, rozgryzłeś nas, my programiści jesteśmy tajemnym zgromadzeniem, które za wszelką cenę będzie bronić naszych sekretów i odpychać nowicjuszy. A nowe funkcje języka są tylko po to, aby wywoływać ból głowy u noobków, którzy chcieli napisać grę w kilku linijkach.

  5. MSM:
    June 4th, 2011 o 18:06

    Zarówno `znawcy tematu` jak i `programiści funkcyjni` mają rację :) (Chociaż IMO ta imitacja nie jest wcale ‘kiepska’ – kiepska imitacja to były metody anonimowe w C# ale na szczęście teraz już pojawiła się lambda :)

    Chociaż pewnie ze wsparciem tych ‘domowych’ metod lambda kiepsko, nie słyszałem o wbudowanych funkcjach typu map albo fold używających Runnable (a może się mylę)

    @J.P. (znaczące inicjały btw.) – rozgryzłeś nas, tak naprawdę Tajne Zgromadzenie Programistów ukrywa język który pozwala napisać Worda w paru komendach [rofl] gdyż spowodowałoby to masowe zwolnienia informatyków.

  6. Wibowit:
    June 4th, 2011 o 18:17

    MSM:
    map, ani fold nie mogą opierać się na Runnable, bo run() nic nie zwraca, ani nie przyjmuje. Trzeba to jakoś inaczej opakować, np tak jak to zrobili kolesie z: http://functionaljava.org/

  7. back2life:
    June 4th, 2011 o 21:38

    Zarówno `znawcy tematu` jak i `programiści funkcyjni` mają rację :) (Chociaż IMO ta imitacja nie jest wcale ‘kiepska’ – kiepska imitacja to były metody anonimowe w C# ale na szczęście teraz już pojawiła się lambda :)

  8. Kos:
    June 5th, 2011 o 16:46

    @Janusz Pawlak- programowanie jest w tych czasach jednoznacznie coraz łatwiesze i coraz szerzej dostępne. Już dziś jest zupełnie normalne, że licealista pisze gry komputerowe, gimnazjalista zrobi ojcu stronę internetową w HTML, PHP i z bazą danych pod spodem, a ambitniejsza pani domu – już od lat! – podliczy w excelu budżet domowy (dataflow programming w czystej postaci!).

    Wykluczenie cyfrowe? Też mi coś.. :) Wiedza jest w książkach, jest w internecie, trzeba tylko po nią sięgnąć. Jedyne, co może doprowadzić do wykluczenia, to brak chęci nauki. Europosłowie na pewno się zgodzą.

  9. Dab:
    June 6th, 2011 o 21:10

    No proszę, trolling is a art. :)

Comments are disabled.
 


© 2023 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.