Differences

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

Link to this comparison view

poo-ca-cd:laboratoare:static-final [2021/09/18 21:09]
miruna_maria.fatu [Singleton Pattern]
poo-ca-cd:laboratoare:static-final [2023/10/29 16:03] (current)
calin.precupetu
Line 250: Line 250:
  
 {{ :​poo-ca-cd:​laboratoare:​singleton2.png?​500 |}} {{ :​poo-ca-cd:​laboratoare:​singleton2.png?​500 |}}
-                    Clients may not even realize that they’re working with the same object all the time. 
  
 Exemple din API-ul Java: [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​Runtime.html | java.lang.Runtime]],​ [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​awt/​Toolkit.html | java.awt.Toolkit]] Exemple din API-ul Java: [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​Runtime.html | java.lang.Runtime]],​ [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​awt/​Toolkit.html | java.awt.Toolkit]]
Line 339: Line 338:
 O clasă de tip Singleton poate fi extinsă, iar metodele ei suprascrise,​ însă într-o clasă cu metode statice acestea nu pot fi suprascrise (//​overriden//​) (o discuție pe aceasta temă puteți găsi [[http://​geekexplains.blogspot.ro/​2008/​06/​can-you-override-static-methods-in-java.html | aici]], și o comparație între static și dynamic binding [[http://​geekexplains.blogspot.ro/​2008/​06/​dynamic-binding-vs-static-binding-in.html | aici]]). O clasă de tip Singleton poate fi extinsă, iar metodele ei suprascrise,​ însă într-o clasă cu metode statice acestea nu pot fi suprascrise (//​overriden//​) (o discuție pe aceasta temă puteți găsi [[http://​geekexplains.blogspot.ro/​2008/​06/​can-you-override-static-methods-in-java.html | aici]], și o comparație între static și dynamic binding [[http://​geekexplains.blogspot.ro/​2008/​06/​dynamic-binding-vs-static-binding-in.html | aici]]).
  
-=== Tutorial debugging în IntelliJ ===+==== Deep copy. Shallow copy ==== 
 + 
 +Pentru început, ne propunem să ne familiarizăm cu noțiunea de copie în Java.  
 + 
 +Noțiunea de //reference copy// implică copierea unei **referințe** care pointeaza către un obiect. 
 +Exemplu: Dacă avem un obiect de tipul Car, iar variabila myCar pointeaza către acesta, prin crearea unei copii de referință vom obține două variabile myCar ce pointeaza către același obiect de tipul Car.  
 +{{ :​poo-ca-cd:​laboratoare:​shallow.jpg?​300 |}} 
 + 
 +Noțiunea de //object copy// creează însă o copie a obiectului în sine. Deci, dacă am copia din nou obiectul Car, am crea o copie a obiectului în sine, precum și o a doua variabilă de referință ce face referire la acel obiect copiat. 
 +{{ :​poo-ca-cd:​laboratoare:​deep.jpg?​300 |}} 
 + 
 +**//Shallow copy//** se referă la copierea obiectului „principal”,​ dar nu copiază obiectele "​interioare",​ acestea fiind "​împărtășite"​ doar de obiectul original și copia acestuia. De exemplu, dacă pentru un obiect de tip Person, am crea un al doilea obiect Person, ambele obiecte ar avea aceleași obiecte Name și Address întrucât schimbarea unuia dintre acestea implică modificarea peste tot unde se regăsește referința obiectului modificat.  
 + 
 +Putem spune astfel că cele două obiecte Person nu sunt independente - dacă este modificat obiectul Name al unui obiect Person, schimbarea se va reflecta și în celălat obiect de acest tip. 
 + 
 +<code java> 
 +public class Person { 
 +    private Name name; 
 +    private Address address; 
 + 
 +    public Person(Person firstPerson) { 
 +         ​this.name = firstPerson.name;​ 
 +         ​this.address = firstPerson.address;​ 
 +    } 
 +
 +</​code>​ 
 + 
 +Spre deosebire de shallow copy, **//deep copy//** este o copie complet independentă a unui obiect. Dacă am copia obiectul Person, am copia întreaga structură a obiectului. În acest caz, o modificare a obiectului Adress nu va fi reflectată în cealalt obiect. Dacă aruncăm o privire asupra codului din exemplul următor, se observă că nu este folosit doar un //copy constructor//​ pentru obiectul Person, dar și //copy constructors//​ pentru obiectele interioare. 
 + 
 +<code java> 
 +public class Person { 
 +    private Name name; 
 +    private Address address; 
 + 
 +    public Person(Person otherPerson) { 
 +         ​this.name ​   =  new Name(otherPerson.name);​ 
 +         ​this.address =  new Address(otherPerson.address);​ 
 +    } 
 +
 +</​code>​ 
 + 
 +==== Tutorial debugging în IntelliJ ​====
  
 Luând în considerare următorul scenariu: Luând în considerare următorul scenariu:
Line 386: Line 426:
   * Watch expression - în caseta de Variables apoi + se poate inițializa o variabilă nouă sau una deja existentă care să fie urmărită pe parcursul sesiunii de debug   * Watch expression - în caseta de Variables apoi + se poate inițializa o variabilă nouă sau una deja existentă care să fie urmărită pe parcursul sesiunii de debug
   * Set Value - putem modifica comportamentul programului fară să schimbăm codul sursă, pentru orice variabilă din caseta de Variables click dreapta -> Set Value și putem observa cum se modifică programul cu noua valoare dată   * Set Value - putem modifica comportamentul programului fară să schimbăm codul sursă, pentru orice variabilă din caseta de Variables click dreapta -> Set Value și putem observa cum se modifică programul cu noua valoare dată
 +
 +==== Utilizarea clasei HashMap. Exemple ====
 +Clasa HashMap este un dicționar (tabelă de dispersie / hashtable), o colecție de perechi cheie-valoare unde avem o mapare între cheia unică în colecție și valoarea asociată acesteia, iar această clasă poate fi găsită în pachetul java.util. Principalele metode ale acestei clase sunt:
 +  * ''​put(K key, V value)''​ - adaugă o pereche cheie-valoare sau înlocuiește valoarea asociată unei chei deja existente în HashMap.
 +  * ''​get(Object key)''​ - accesează valoarea asociată unei chei din HashMap.
 +  * ''​size()''​ - returnează numărul de elemente din HashMap.
 +  * ''​containsKey(Object key)''​ - verifică dacă cheia există în HashMap.
 +  * ''​remove(Object key)''​ - șterge o pereche cu cheia respectivă din HashMap.
 +  * ''​clear()''​ - șterge toate elementele din HashMap.
 +
 +Pentru a putea parcurge elementele unui HashMap se poate folosi for-each. Un exemplu de utilizare a metodelor clasei HashMap și de parcurgere a elementelor stocate de această clasă este următorul:
 +<code java5>
 +import java.util.HashMap;​
 +import java.util.Map;​
 +
 +public class Main {
 +    public static void main(String[] args) {
 +        HashMap<​String,​ Integer> grades = new HashMap<>​();​
 +        grades.put("​Celentano",​ 5);
 +        grades.put("​Firicel",​ 8);
 +        grades.put("​Brinzoi",​ 9);
 +        grades.put("​Bobita",​ 10);
 +
 +        System.out.println("​Firicel'​s grade: "+ grades.get("​Firicel"​));​
 +
 +        grades.put("​Firicel",​ 10);
 +        System.out.println("​Firicel'​s grade: "+ grades.get("​Firicel"​));​
 +
 +        for (Map.Entry<​String,​ Integer> entry: grades.entrySet()) {
 +            System.out.println(entry.getKey() + ": " + entry.getValue());​
 +        }
 +    }
 +}
 +</​code>​
 +
  
 ==== Exerciții ==== ==== Exerciții ====
-  - (**3p**) Să se implementeze o clasă ''​PasswordMaker''​ ce generează, folosind ''​RandomStringGenerator'',​ o parolă pornind de la datele unei persoane. Această clasă o să conțină următoarele +  - Pentru a rezolva laboratorul aveti urmatorul contest pe LambdaChecker ​[[https://​beta.lambdachecker.io/​contest/​55/​problems?​page=1 | contest]] 
-    * o constantă MAGIC_NUMBER având orice valoare doriți  +  - **(0 puncte)** Folosind pașii de mai sus și debugger-ulreparați codul din pachetul ​''​vault''​ din cadrul ​[[https://github.com/oop-pub/oop-labs/tree/master/src/lab4 scheletului laboratorului]] (același care este prezentat în cadrul tutorialului de debug). 
-    * un String constant MAGIC_STRING,​ lung de minim 20 de caractere, generat random +  -  Aveți de implementat o mini aplicație de tip queries dintr-o bază de date cu dealershipuri și selleri de masini. Fiecare dealership are o colecție de asocieri dintre brandurile de masini vandute și pretul lor, de tip dicționar, iar fiecare seller are o listă de branduri de masina pe care le vinde.  
-    * un constructor care primeșteun String numit ''​name''​ +      - **(2 puncte)** Având ​la bază scheletul ​de cod, faceți clasa Database, ​care se ocupă cu gestionarea bazei de date dealershipurilor și a selleriloro clasă de tip Singleton cu implementare de tip lazy. Această clasă va conține o listă de dealershipuri și o listă ​de selleri. Faceți aceste liste de tip final. 
-    o metodă ''​getPassword()''​ care va returna parola  +      - **(1 punct)** Clasa ''​Dealership'' ​are doua câmpuri: nume și un dicționar unde sunt stocate brandurile de masini, fiecare brand fiind asociat cu pretul sau la dealershipul respectiv. În această clasă, implementați următoarele: 
-      ​parola se construiește concatenând următoarele șiruri: +          - metoda ''​averagePrice''​, care calculează media pretului masinilor din Dealership
-        ​un șir random ​de lungime MAGIC_NUMBERgenerat cu ''​RandomStringGenerator'' ​și cu un alfabet obținut ​din 10 caractere obținute random din MAGIC_STRING +          copy constructorul clasei 
-        * și șirul format prin conversia la String a lungimii lui name + un număr întreg generat random din intervalul ​[0, 100] +          - metoda ''​getPriceForBrand''​, care primește ca parametru ​de intrare numele unui brand și întoarce pretul acestuia
-    * Pentru subșiruri și alte metode utile consultați documentația clasei ​[[http://docs.oracle.com/javase/8/docs/api/java/lang/​String.html ​String]] +      - **(1 punct)** Clasa ''​Seller'' ​are doua câmpuri: nume si lista brandurilor pe care acesta le vinde. În această clasa implementați copy constructor. 
-  - (**3p**) Modificați implementarea clasei PasswordMaker astfel încât să respecte conceptul ​de **Singleton pattern** (să permită instanțierea unui singur obiect) +      ​- ​**(2 puncte)** În clasa ''​Database'' ​implementați următoarele metode: 
-        ​Pornind de la exemplul ​de Singleton din textul laboratorului implementați o versiune ​care urmează principiul ​de Eager Initialization (singura instanță ​clasei este creată la pornirea aplicațieiindiferent dacă este necesar sau nu) +          - ''​getAllDealerships''​ - întoarce lista de delaershipuri 
-        * Implementați o versiune ​de Singleton în care variabila ​''​instance'' ​este inițializată într-un bloc static +          - ''​getAllSellers''​ - intoarce lista de selleri 
-        * Adăugați un contor care să numere de câte ori a fost accesată metoda ''​getInstance()''​. ​E nevoie ca acest contor să fie static? +          - ''​getDealershipByBrand''​ - primește ca parametru numele unui brand și întoarce lista cu dealershipurile ​care detin brandul respectiv 
-        * //Temă de gândire:// Ce se va întâmplă dacă folosim conceptul de Singleton pattern într-un program paralelizat, care rulează pe mai multe linii de execuție (thread-uri)Ce probleme ar putea să apară? +          - ''​getSellerByBrand''​ - primește ​ca parametru numele unui brand și întoarce lista cu sellerii care vand brandul respectiv. 
-  (**3p**) Să se implementeze o clasă ​''​MyImmutableArray''​ care să conțină: +          - ''​getDealershipsByAveragePrice''​ - întoarce lista cu dealershipuri sortate crescător în funcție de pretul lor mediu. 
-    un field ''​ArrayList<​Integer>​ immutableArray;​'' ​neinițializat în primă fază +          - ''​getDealershipsByPriceForBrand'' ​- primește ca parametru numele unui brand și întoarce lista cu dealershipurile care detin acel brand, sortate după pretul acestuia în ordine crescătoare. 
-    * un constructor ​care primește ​un ArrayList<​Integer> ​și copiază toate elementele din acel array în ''​immutableArray''​ +      ​-  ​**(1 punct)** În clasa ''​Seller''​ implementați următoarele metode, care vor apela metodele corespunzătoare din clasa ''​Database'':​ 
-    o metodă getArray implementată în așa fel încât field-ul ''​immutableArray''​ să rămână immutable (Hint: ​[[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​util/​Collections.html#​unmodifiableList-java.util.List- ​| Collections.unmodifiableList()]]) +          ​- ''​getAllSellers''​ 
-  (**1p**) Testați clasa ''​MyImmutableArray'' ​demonstrând faptul că instanțele acestei clase sunt imutabile +          - ''​getAllDealerships''​ 
-==== Resurse ==== +          - ''​getSellersByBrand''​ 
-  * {{:poo-ca-cd:​laboratoare:​static-final-singleton:schelet_lab4.zip|Arhiva zip cu clasa RandomStringGenerator.java}}+          - ''​getDealershipsByBrand''​ 
 +          - ''​getDealershipsByAveragePrice''​ 
 +          - ''​getDealershipsByPriceForBrand''​ 
 +      - **(2 puncte)** În clasa Dealership implementați următoarele metode, care vor apela metodele corespunzătoare din clasa ''​Database''​ (atenție, aici metodele trebuie ​să întoarcă rezultate imutabile, sub forma de deep copy, folosind modalitatea prezentată în laborator, folosind ​[[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​util/​Collections.html | Collections.unmodifiableList()]] ​pentru ca evita posibilitatea de a modifica rezultatele,​ care sunt read-only): 
 +          - ''​getAllSellers''​ 
 +          - ''​getAllDealerships''​ 
 +          - ''​getSellersByBrand''​ 
 +          - ''​getDealershipsByBrand''​ 
 +          - ''​getDealershipsByAveragePrice''​ 
 +          - ''​getDealershipsByPriceForBrand''​ 
 +      ​- **(1 punct)** În clasa ''​Database'',​ adăugați un contor drept câmp al clasei, de tip static, care va număra instanțierile clasei în cadrul metodei ​''​getDatabase''​, unde se face instanțierea clasei. Implementați metoda ''​getNumberOfInstances()''​ din ''​Database'',​ care întoarce numărul de instanțieri. 
 +     
 + 
 +<note tip> 
 +Pentru sortarea unui ArrayList (despre care am discutat în cadrul [[poo-ca-cd:​laboratoare:​agregare-mostenire|laboratorului trecut]], ​ puteți folosi metoda sort() din cadrul clasei ArrayList: 
 +<code java> 
 +ArrayList<​String>​ animals = new ArrayList<>​();​ 
 +animals.add("​Dog"​);​ 
 +animals.add("​Cat"​);​ 
 +animals.add("​Sheep"​);​ 
 + 
 +animals.sort(new Comparator<​String>​() { 
 +    @Override 
 +        public int compare(String o1, String o2) { 
 +            return o1.compareTo(o2);​ 
 +        ​} 
 +}); 
 +</​code>​ 
 +</​note>​ 
 + 
 +<note tip> 
 +Pentru shallow copy și deep copy la ArrayList avem în felul următor: 
 +  * shallow copy: 
 +  <code java> 
 +  List<​Student>​ shallowCopy = new ArrayList<>​(list);​ 
 +  </​code>​ 
 +  * deep copy: 
 +  <code java> 
 +  List<​Student>​ deepCopy = new ArrayList<>​();​ 
 +  for (var student: list) { 
 +      // folosind constructor cu deep copy 
 +      deepCopy.add(new Student(student));​ 
 +  } 
 +  return deepCopy; 
 +  </​code>​ 
 +</​note>​
  
poo-ca-cd/laboratoare/static-final.1631988573.txt.gz · Last modified: 2021/09/18 21:09 by miruna_maria.fatu
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