Programarea reactiva in Java. Abordarea reactiva

Luxoft Training
4 min readNov 10, 2021

O continuare a primei noastre serii de articole despre programarea reactiva in Java. In acest articol analizam abordarea reactiva.

Abordarea reactiva

Hai sa ne uitam la un alt exemplu: sa presupunem ca lucram la dezvoltarea unei UI si trebuie sa urmarim click-urile duble. Un click triplu, spre exemplu, va fi considerat ca fiind unul dublu.

Aici click-urile sunt un thread de clickuri de mouse (1, 2, 1, 3 in schema de mai sus). Astfel ca avem nevoie sa le grupam. Pentru a face asta folosim un throttle operator. Daca doua evenimente (doua click-uri) au avut loc in limita a 250ms, ele ar trebui grupate. Cea de-a doua schema arata aceste valori grupate (1, 2, 1, 3). Acesta este un thread de date, dar care sunt deja procesate — in acest caz grupate.

Threadul initial a fost transformat in altul. Apoi trebuie sa obtinem lungimea listei (1, 2, 1, 3). Aplicam filtrul, lasand doar acele valori mai mari sau egale cu 2. In schema de mai jos, doar doua elemente au mai ramas (2, 3) — acestea au fost doar click-uri duble. Astfel ca am transformat thread-ul initial intr-un thread cu click-uri duble.

Aceasta este programarea reactiva: avem input threads, le trecem prin handlers, si avem un output thread. In acest caz, toate procesarea este facuta asincron, i.e., nimeni nu asteapta nimic.

O alta metafora buna este un sistem de alimentare cu apa: avem tevi conectate intre ele, cateva robinete, poate niste filtre, elemente care incalzesc sau racesc (acestia pot sa fie operatorii) si tevile se despica sau se unesc. Sistemul functioneaza. Apa curge. Acelasi lucru se intampla si in programarea reactiva, dar in locul unui flux de apa avem un flux de date.

Putem sa ne gandim la un proces bazat pe fluxuri pentru a face supa. Spre exemplu, sarcina este sa gatim un volum cat mai mare de supa in mod eficient. De obicei, luam o oala, punem apa in ea, taiem legume etc. Nu este un flux, ci o abordare traditionala unde gatim o portiune din volumul de supa. Apoi dupa ce aceasta e gata, luam urmatorul vas, apoi urmatorul si asa mai departe. Astfel ca trebuie sa asteptam pana cand apa incepe sa fiarba din nou, pana cand se fierb legumele si tot asa. Toate aceste lucruri necesita timp.

Imagineaza-ti o alta metoda: intr-o teava (indeajuns de mare incat sa umple un vas), apa este incalzita si avem deja legumele facute. Legumele intra intregi ca input si ies taiate rondele ca output. La un moment dat totul se amesteca. Aceasta este cea mai eficienta metoda de a gati, un fel de banda rulanta. Asta este idea din spatele abordarii reactive.

Observable

Acum hai sa ne uitam la codul folosit pentru a publica evenimente:

Observable.just ne permite sa includem mai multe valori intr-un thread. Si daca ordinary reactive threads contin valori extinse in timp, aici le punem pe toate in acelasi timp, adica sincron. In exemplul pe care il folosim noi, acestea sunt numele oraselor la care ne putem abona.

(Publisher) a publicat acele valori, si Observers s-au abonat la ele si au tiparit acele valori din cadrul thread-ului.

Arata precum data streams in Java 8. Ambele sunt synchronous streams. Atat aici cat si in Java 8, stim deja lista valorilor. Dar daca am fi folosit un stream Java 8 standard, nu am fi putut sa adaugam ceva. Nu putem adauga nimic unui stream — este sincron. In exemplul nostru, thread-urile sunt asincron, ceea ce inseamna ca un eveniment nou poate aparea oricand. Daca apare un nou oras, acesta poate sa fie adaugat la thread, si reactive operators vor aborda acest lucru. Am adaugat evenimente si ne-am abonat imediat la ele:

locations.subscribe(s -> System.out.println(s)))

Putem sa adaugam o valoare noua oricand si aceasta va aparea dupa o perioada de timp. Cand apare o valoare noua, ii cerem programului sa o printeze si sa ofere o lista de valori.

In acel caz, nu doar ca putem indica ce ar trebui sa se intample cand sunt adaugate valori noi dar putem si sa abordam aceste scenarii ca fiind erori in cadrul fluxului de date sau la finalul acestuia. Da, desi fluxurile de date sunt de multe ori fara un final (vezi articolul nostru anterior despre senzorul de caldura sau cel de fum), multe fluxuri se pot termina: spre exemplu, un flux de date din cadrul unui server sau microservice. La un anumit punct, serverul inchide conexiunea, si apare nevoie de a reactiona intr-un fel la acest lucru.

Articolul original poate sa fie citit aici.

Vrei sa inveti sa programezi cu Java sau sa iti imbunatatesti abilitatile de programare in Java? Parcurge cursurile noastre.

Originally published at https://www.luxoft-training.ro.

--

--