Differences

This shows you the differences between two versions of the page.

Link to this comparison view

poo-ca-cd:laboratoare:visitor [2024/11/10 16:55]
silvia_elena.nistor
poo-ca-cd:laboratoare:visitor [2024/11/13 09:56] (current)
silvia_elena.nistor [Exerciţii]
Line 1: Line 1:
-===== Laboratorul ​7: Visitor pattern =====+===== Laboratorul ​6: Visitor pattern =====
  
 **Video introductiv:​** [[https://​www.youtube.com/​watch?​v=_mfLYYInv6c| link ]] **Video introductiv:​** [[https://​www.youtube.com/​watch?​v=_mfLYYInv6c| link ]]
Line 9: Line 9:
 ==== Visitor Design Pattern ==== ==== Visitor Design Pattern ====
  
-<​note>​Design pattern-urile reprezintă soluții generale și reutilizabile ale unei probleme comune în design-ul software. Un design pattern este o descriere a soluției sau un template ce poate fi aplicat pentru rezolvarea problemei, nu o bucata ​de cod ce poate fi aplicata ​direct. În general pattern-urile orientate pe obiect arată relațiile și interacțiunile dintre clase sau obiecte, fără a specifica însă forma finală a claselor sau a obiectelor implicate.</​note> ​+<​note>​Design pattern-urile reprezintă soluții generale și reutilizabile ale unei probleme comune în design-ul software. Un design pattern este o descriere a soluției sau un template ce poate fi aplicat pentru rezolvarea problemei, nu o bucată ​de cod ce poate fi aplicată ​direct. În generalpattern-urile orientate pe obiect arată relațiile și interacțiunile dintre clase sau obiecte, fără a specifica însă forma finală a claselor sau a obiectelor implicate.</​note> ​
  
-//Visitor// este un **behavioral ​design pattern** ce oferă posibilitatea de a adăuga în mod __extern__ funcționalități pe o întreagă ierarhie de clase fără să fie nevoie să modificăm efectiv structura acestora. ​+//Visitor// este un **behavioural ​design pattern** ce oferă posibilitatea de a adăuga în mod __extern__ funcționalități pe o întreagă ierarhie de clasefără să fie nevoie să modificăm efectiv structura acestora. ​
  
-Acest pattern este behavioral ​(//​comportamental//​) pentru că definește modalități de comunicare între obiecte. ​+Acest pattern este behavioural ​(//​comportamental//​) pentru că definește modalități de comunicare între obiecte. ​
  
 === Aplicabilitate === === Aplicabilitate ===
  
 Pattern-ul **Visitor** este util când: Pattern-ul **Visitor** este util când:
-  * se doreşte prelucrarea unei //structuri complexe//, ce cuprinde mai multe obiecte de //tipuri diferite//​ +  * se dorește prelucrarea unei //structuri complexe//, ce cuprinde mai multe obiecte de //tipuri diferite//​ 
-  * se dorește definirea de operații specifice pentru aceeași structură, fără a polua interfeţele claselor implicate, cu multe detalii specifice algoritmilor. Vizitatorul centralizează logica comună, păstrând în același timp detaliile specifice în interiorul acestuia. +  * se dorește definirea de operații specifice pentru aceeași structură, fără a polua interfețele claselor implicate, cu multe detalii specifice algoritmilor. Vizitatorul centralizează logica comună, păstrând în același timp detaliile specifice în interiorul acestuia. 
-  * ** clasele ce se doresc prelucrate se modifică rar, în timp ce operaţiile de prelucrare se definesc des**. Vizitatorul permite adăugarea de noi funcționalități fără modificarea claselor existente.+  * ** clasele ce se doresc prelucrate se modifică rar, în timp ce operațiile de prelucrare se definesc des**. Vizitatorul permite adăugarea de noi funcționalități fără modificarea claselor existente.
  
 === Structură ===  === Structură === 
Line 44: Line 44:
  
 **Visitable:​** **Visitable:​**
-   * Este o interfață pentru obiecte pe care pot fi aplicate operațiile+   * Este o interfață pentru obiecte pe care pot fi aplicate operațiile.
    * Această operație permite unui obiect să fie "​vizitat"​ de către un obiect "​Visitor"​.    * Această operație permite unui obiect să fie "​vizitat"​ de către un obiect "​Visitor"​.
    * Exemplu: Interfața Visitable cu metoda accept(Visitor visitor).    * Exemplu: Interfața Visitable cu metoda accept(Visitor visitor).
  
 **ConcreteVisitable:​** **ConcreteVisitable:​**
-   * Aceste clase implementează interfața ​Visitable ​sau clasa și definesc operația accept.+   * Aceste clase implementează interfața sau clasa Visitable ​și definesc operația accept.
    * Prin intermediul acestei operații, obiectul "​Vizitabil"​ primește un obiect "​Visitor"​.    * Prin intermediul acestei operații, obiectul "​Vizitabil"​ primește un obiect "​Visitor"​.
    * Exemplu: Clasele ConcreteElementA,​ ConcreteElementB,​ etc., care implementează interfața Visitable și definesc metoda accept.    * Exemplu: Clasele ConcreteElementA,​ ConcreteElementB,​ etc., care implementează interfața Visitable și definesc metoda accept.
  
  
-<note tip> ​Flowul ​aplicării acestui pattern:+<note tip> ​Flow-ul ​aplicării acestui pattern:
   -  Când un client dorește să efectueze operații pe obiectele vizitabile, el creează un obiect vizitator corespunzător,​ le "​vizitează"​ apelând metoda accept, iar fiecare obiect vizitabil interacționează cu vizitatorul prin intermediul metodelor visit.   -  Când un client dorește să efectueze operații pe obiectele vizitabile, el creează un obiect vizitator corespunzător,​ le "​vizitează"​ apelând metoda accept, iar fiecare obiect vizitabil interacționează cu vizitatorul prin intermediul metodelor visit.
   -  Acest pattern oferă o modalitate de a separa algoritmii de obiectele pe care operează, facilitând extinderea și adăugarea de noi operații fără a modifica clasele obiectelor vizitabile.   -  Acest pattern oferă o modalitate de a separa algoritmii de obiectele pe care operează, facilitând extinderea și adăugarea de noi operații fără a modifica clasele obiectelor vizitabile.
Line 63: Line 63:
 **Visitor și structurile de date** **Visitor și structurile de date**
  
-Aparent, folosirea lui //accept// este artificială. De ce nu declanşăm vizitarea unui obiect, apelând **direct** //​v.visit(e)//​ atunci când dorim vizitarea unui obiect oarecare? Răspunsul vine însă chiar din situaţiile în care vrem să folosim pattern-ul; vrem să lăsăm structura internă a colecţiei să facă aplicarea vizitatorilor. Cu alte cuvinte vizitatorul se ocupă de fiecare obiect în parte, iar colecţia îl "​plimbă"​ prin elementele sale. De exemplu, când dorim să vizităm un arbore: +Aparent, folosirea lui //accept// este artificială. De ce nu declanșăm vizitarea unui obiect, apelând **direct** //​v.visit(e)//​ atunci când dorim vizitarea unui obiect oarecare? Răspunsul vine însă chiar din situațiile în care vrem să folosim pattern-ul; vrem să lăsăm structura internă a colecţiei să facă aplicarea vizitatorilor. Cu alte cuvintevizitatorul se ocupă de fiecare obiect în parte, iar colecţia îl "​plimbă"​ prin elementele sale. De exemplu, când dorim să vizităm un arbore: 
-  * declanşarea vizitării se va face printr-un apel ''​accept''​ pe un prim obiect (e.g. rădacina ​arborelui) +  * declanşarea vizitării se va face printr-un apel ''​accept''​ pe un prim obiect (e.g. rădăcina ​arborelui) 
-  * elementul curent este vizitatprin apelul ''​v.visit(this)''​+  * elementul curent este vizitat prin apelul ''​v.visit(this)''​
   * pe lângă vizitarea elementului curent, este necesar sa declanşăm vizitarea //tuturor elementelor accesibile din elementul curent// (e.g. nodurile-copil din arbore etc). Realizăm acest lucru apelând ''​accept''​ pe //fiecare// dintre aceste elemente. Acest comportament depinde de logica structurii.   * pe lângă vizitarea elementului curent, este necesar sa declanşăm vizitarea //tuturor elementelor accesibile din elementul curent// (e.g. nodurile-copil din arbore etc). Realizăm acest lucru apelând ''​accept''​ pe //fiecare// dintre aceste elemente. Acest comportament depinde de logica structurii.
 </​note>​ </​note>​
Line 117: Line 117:
  
 Ne interesează să interogăm toţi angajaţii noştri asupra //venitului lor total//. Observăm că: Ne interesează să interogăm toţi angajaţii noştri asupra //venitului lor total//. Observăm că:
-  * anagajaţii obişnuiţi au salariul ca unic venit+  * angajaţii obişnuiţi au salariul ca unic venit
   * şefii posedă, pe lângă salariu, un posibil bonus   * şefii posedă, pe lângă salariu, un posibil bonus
  
-Varianta la îndemână ar fi să definimîn fiecare din cele doua clase, câte o metodă, //​getTotalRevenue()//,​ care întoarce salariul pentru angajaţi, respectiv suma dintre salariu şi bonus pentru şefi:+Varianta la îndemână ar fi să definim în fiecare din cele doua clase, câte o metodă, //​getTotalRevenue()//,​ care întoarce salariul pentru angajaţi, respectiv suma dintre salariu şi bonus pentru şefi:
  
 <code java> <code java>
Line 198: Line 198:
  
 Secvenţele de cod de mai sus definesc: Secvenţele de cod de mai sus definesc:
-  * o interfaţă,​ **Visitor**,​ ce reprezintă un //​algoritm//​ oarecare, ce va putea vizita orice clasă. Observaţi definirea câte //unei metode visit(...)//​ pentru //fiecare clasă ce va putea fi vizitată//+  * o interfaţă,​ **Visitor**,​ ce reprezintă un //​algoritm//​ oarecare, ce va putea vizita orice clasă. Observaţi definirea câte //unei metode visit(...)//​ pentru //fiecare clasă ce va putea fi vizitată//.
   * o interfaţă,​ **Visitable**,​ a carei metodă ''​accept(Visitor)''​ permite rularea unui algoritm pe structura curentă. ​   * o interfaţă,​ **Visitable**,​ a carei metodă ''​accept(Visitor)''​ permite rularea unui algoritm pe structura curentă. ​
   * implementări ale metodei ''​accept(Visitor)'',​ în cele două clase, care, pur şi simplu, solicită vizitarea instanţei curente de către vizitator. ​   * implementări ale metodei ''​accept(Visitor)'',​ în cele două clase, care, pur şi simplu, solicită vizitarea instanţei curente de către vizitator. ​
-  * o implementare a unei operații aplicabilă pe obiectele de tip Visitable+  * o implementare a unei operații aplicabilă pe obiectele de tip Visitable.
  
 În exemplul de mai sus, putem identifica : În exemplul de mai sus, putem identifica :
Line 209: Line 209:
 === Double-dispatch === === Double-dispatch ===
  
-Mecanismul din spatele pattern-ului Visitor poartă numele de **double-dispatch**. Acesta este un concept ​raspândit, şi se referă la faptul că metoda apelată este determinată la //runtime// de doi factori. În exemplul Employee-Manager,​ efectul ​vizitarii, solicitate prin apelul ''​e.accept(v)'',​ depinde de:+Mecanismul din spatele pattern-ului Visitor poartă numele de **double-dispatch**. Acesta este un concept ​răspândit, şi se referă la faptul că metoda apelată este determinată la //runtime// de doi factori. În exemplul Employee-Manager,​ efectul ​vizitării, solicitate prin apelul ''​e.accept(v)'',​ depinde de:
   * tipul elementului vizitat, ''​e''​ (//​Employee//​ sau //​Manager//​),​ pe care se invocă metoda   * tipul elementului vizitat, ''​e''​ (//​Employee//​ sau //​Manager//​),​ pe care se invocă metoda
   * tipul vizitatorului,​ ''​v''​ (//​RevenueVisitor//​),​ care conţine implementările metodelor //visit//   * tipul vizitatorului,​ ''​v''​ (//​RevenueVisitor//​),​ care conţine implementările metodelor //visit//
Line 260: Line 260:
 ==== Exerciţii ==== ==== Exerciţii ====
  
-Dorim să prelucrăm ​bucăți de text pe care să le convertim ​în diferite ​formate, momentan dokuwiki ​și markdown. Pentru un design decuplat între ​obiectele ​prelucrate și tipurile de formate dorite, implementați conversia folosind patternul Visitor.+Dorim să prelucrăm ​forme geometrice, ​pe care să le afișăm ​în diverse ​formate: text și JSON https://​datatracker.ietf.org/​doc/​html/​rfc8259. Pentru un design decuplat între ​formele ​prelucrate și tipurile de formate dorite, implementați conversia folosind patternul Visitor.
  
-      * Fișierul **[[https://​github.com/​oop-pub/​oop-labs/​tree/​master/​src/​lab7|README]]** din scheletul ​de cod cuprinde informațiile necesare designului dorit. +Problema de pe DevMind va avea două task-uri, corespunzătoare celor două tipuri ​de VisitorPentru simplitatea implementării acestor Visitors, vă sugerăm să urmăriți TODO-urile din schelet. 
-        * implementați structura de clase din diagrama din README + 
-        * implementați TODO-urile din scheletul de cod +      * Vom avea trei tipuri de forme geometrice ​care implementează interfața comună "​**Shape**":​ **Dot**, **Circle**, **Rectangle**. Aceste tipuri ​de forme vor accepta obiecte Visitor pentru a putea permite afișarea lor în cele două formate
-      * Pentru simplitatea testării scheletul oferă clasa ''​Test'' ​care oferă bucățile de text pe care să le prelucrați+      Vom avea două tipuri ​de Visitor care implementează interfața comună "**Visitor**"​**TextVisitor** și **JsonVisitor**Fiecare Visitor va implementa metoda visit(), care va aplica modalitatea de afișare specifică pe obiectul primit ca parametru. 
-        dacă folosiți IntelliJ creați proiect din scheletul ​de laborator: File -> New Project -> select Java -> select the skel folder +      * Scheletul conține în fiecare clasă copil a tipului Shape, câmpuri specifice formei geometricePentru acestea, va trebui să creați getters și setters.
-      ​În implementare va trebui sa folositi clasa [[https://docs.oracle.com/​en/​java/​javase/​12/​docs/​api/​java.base/​java/​lang/​StringBuilder.html|StringBuilder]]. Aceasta este o clasă mutabilă ​(//mutable//), spre deosebire de String, care e imutabilă (//​immutable//​)Vă recomandăm [[https://​www.geeksforgeeks.org/​string-vs-stringbuilder-vs-stringbuffer-in-java/​|acest link]] pentru un exemplu si explicații despre diferențele dintre ele.+
       * //Tips for faster coding//:       * //Tips for faster coding//:
-        * atunci ​cand creati ​clasa care implementeaza ​interfata ​sau o clasa cu metode abstracte, nu scrieti ​de mana antetul ​fiecarei ​metode, ci folositi-va de IDE. +        * atunci ​când creați ​clasă ​care implementează ​interfață ​sau o clasă ​cu metode abstracte, nu scrieți ​de mână ​antetul ​fiecărei ​metode, ci folosiți-vă de IDE. 
-        * In Intellij va aparea ​cu rosu imediat ​dupa ce scrieti ​extends.../​implements... ​Dati alt-enter sau option-enter (pe mac), si vi se vor genera metodele pe care trebuie ​sa le implementati, voi completand ​apoi continutul ​lor. +        * în Intellij va apărea ​cu roșu imediat ​după ce scrieți ​extends.../​implements... ​Dați alt-enter sau option-enter (pe mac), și vi se vor genera metodele pe care trebuie ​să le implementați, voi completând ​apoi conținutul ​lor. 
-        * generati constructorii ​folosind IDE-ul+        * generați getters/​setters ​folosind IDE-ul 
 + 
 +Exemplu de format text 
 + 
 +   ​Circle - radius = 30 
 + 
 + 
 +Exemplu de format JSON 
 + 
 + 
 +   { 
 +      "​Circle":​ { 
 +         "​radius":​ 30 
 +      } 
 +   }
  
  
poo-ca-cd/laboratoare/visitor.1731250506.txt.gz · Last modified: 2024/11/10 16:55 by silvia_elena.nistor
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0