User Tools

Site Tools


Problem constructing authldap
laboratoare:static-final
Differences

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

Link to this comparison view

Next revision
Previous revision
laboratoare:static-final [2019/10/19 20:58]
Adriana Draghici created
laboratoare:static-final [2019/10/23 12:19] (current)
Radu Matei [Exerciții]
Line 1: Line 1:
  
-= Static și final =+= Static și final; Singleton Design Pattern ​=
  
 == Obiective == == Obiective ==
 +
 +* Înțelegerea conceptului de static în contextul claselor și instanțelor
 +* Utilizarea keywords-urilor static și final din Java
 +* Folosirea design-pattern-ului Singleton
  
 == Cuvântul-cheie "​final"​. Obiecte immutable == == Cuvântul-cheie "​final"​. Obiecte immutable ==
Line 75: Line 79:
 }  ​ }  ​
 </​code>​ </​code>​
-In acest caz, numarul ​de obiecte create ​in memorie este unul foarte mare. Dintre acestea doar cel rezultat la final este util. Pentru a preveni alocarea ​nejustificata ​a obiectelor de tip String care reprezinta pasi intermediari ​in obtinerea sirului ​dorit putem alege sa folosim clasa StringBuilder ​creata ​special pentru a efectua ​operatii ​pe siruri ​de caractere.+În acest caz, numărul ​de obiecte create ​în memorie este unul foarte mare. Dintre acestea doar cel rezultat la final este util. Pentru a preveni alocarea ​nejustificată ​a obiectelor de tip String care reprezintă pași intermediari ​în obținerea șirului ​dorit putem alege să folosim clasa StringBuilder ​creată ​special pentru a efectua ​operații ​pe șiruri ​de caractere.
 <code java5> <code java5>
 public static String concatenareCuClasaStringBuilder(){  ​ public static String concatenareCuClasaStringBuilder(){  ​
Line 86: Line 90:
 </​code>​ </​code>​
  
-Cuvantul ​cheie final poate fi folosit ​si in alt context ​decat cel prezentat anterior. De exemplu, aplicat unei clase impiedica ​eventuala ​derivare a acestei clase prin mostenire.+Cuvântul ​cheie final poate fi folosit ​și în alt context ​decât ​cel prezentat anterior. De exemplu, aplicat unei clase împiedică ​eventuală ​derivare a acestei clase prin moștenire.
 <code java5> <code java5>
 final class ParentClass { final class ParentClass {
Line 96: Line 100:
 </​code>​ </​code>​
  
-In mod similar, ​in cazul in care aplicam cuvantul ​cheie final unei metode, acest lucru impiedica ​eventuala ​suprascriere a acelei metode+În mod similar, ​în cazul în care aplicăm cuvântul ​cheie final unei metode, acest lucru împiedică ​eventuală ​suprascriere a acelei metode.
 <code java5> <code java5>
 class ParentClass { class ParentClass {
Line 146: Line 150:
 }  ​ }  ​
 </​code>​ </​code>​
-Pentru a observa utilitatea variabilelor statice, vom crea o clasa care tine un contor static ce numara cate instante ​a produs clasa in total.+Pentru a observa utilitatea variabilelor statice, vom crea o clasa care ține un contor static ce numără câte instanțe ​a produs clasa în total.
 <code java5> <code java5>
 class ClassWithStatics { class ClassWithStatics {
Line 175: Line 179:
 }  ​ }  ​
 </​code>​ </​code>​
-Desi am mentionat ​anterior faptul ​ca field-urile ​si metodele statice se acceseaza ​folosind sintaxa ''<​NUME_CLASA>​.<​NUME_METODA/​FIELD>''​ acesta nu este singura abordare ​disponibila in libajul Java. Pentru a referi o entitate ​statica ​ne putem folosi ​si de o instanta ​a clasei ​in care se afla metoda/field-ul accesat. +Deși am menționat ​anterior faptul ​că field-urile ​și metodele statice se accesează ​folosind sintaxa ''<​NUME_CLASA>​.<​NUME_METODA/​FIELD>''​ acesta nu este singura abordare ​disponibilă în libajul Java. Pentru a referi o entitate ​statică ​ne putem folosi ​și de o instanța ​a clasei ​în care se află metodă/field-ul accesat. 
-<note important>​In acest caz nu este relevant ​daca tipul obiectului folosit este diferit de cel al referintei in care e stocat(i.e. avem o referinta ​a clasei Animal care refera ​un obiect de tipul Dog). Pentru apelul unei metode statice se va lua in considerare numai tipul referintei, nu si cel al instantei ​pe care o refera</​note>​+<note important>​În acest caz nu este relevant ​dacă tipul obiectului folosit este diferit de cel al referinței în care e stocat(i.e. avem o referință ​a clasei Animal care referă ​un obiect de tipul Dog). Pentru apelul unei metode statice se va lua în considerare numai tipul referinței, nu și cel al instanței ​pe care o referă</​note>​
 <code java5> <code java5>
 class ClassWithStatics { class ClassWithStatics {
Line 197: Line 201:
 }  ​ }  ​
 </​code>​ </​code>​
-<note warning>Desi putem accesa o entitate ​statica ​folosind o referinta, acest lucru este contraindicat. Field-urile ​si metodele statice ​apartin ​clasei ​si nu ar trebui ​sa fie in nici un fel dependente ​de existenta ​unei instante.</​note>​+<note warning>Deși putem accesa o entitate ​statică ​folosind o referință, acest lucru este contraindicat. Field-urile ​și metodele statice ​aparțin ​clasei ​și nu ar trebui ​să fie in nici un fel dependențe ​de existența ​unei instanțe.</​note>​
  
-Pentru a facilita o initializare ​facila ​a field-urilor statice pe care o clasa le detine, limbajul Java pune la dispozitie ​posibilitatea de a folosi blocuri statice de cod. Aceste blocuri de cod sunt executate atunci ​cand clasa in cauza este incarcata ​de catre masina virtuala ​de java. Incarcarea ​unei clase se face in momentul ​in care aceaste este referita pentru prima data in cod (se creaza ​instanta, se apeleaza ​metoda statica ​etc.) +Pentru a facilita o initializare ​facilă ​a field-urilor statice pe care o clasa le deține, limbajul Java pune la dispoziție ​posibilitatea de a folosi blocuri statice de cod. Aceste blocuri de cod sunt executate atunci ​când clasa în cauza este încărcată ​de către mașina virtuală ​de java. Încărcarea ​unei clase se face în momentul ​în care aceaste este referita pentru prima dată in cod (se crează ​instanță, se apelează ​metodă statică ​etc.) 
-In consecinta, blocul static de cod se va executa intotdeauna inainte ca un obiect ​sa fie creat.+În consecință, blocul static de cod se va execută întotdeauna înainte că un obiect ​să fie creat.
  
 <code java5> <code java5>
Line 221: Line 225:
  
 </​code>​ </​code>​
 +
 +
 +== Singleton Pattern ==
 +
 +Pattern-ul Singleton este utilizat pentru a restricționa numărul de instanțieri ale unei clase la un singur obiect, deci reprezintă o metodă de a folosi o singură instanță a unui obiect în aplicație.
 +
 +=== Utilizari ===
 +
 +Pattern-ul Singleton este util în următoarele cazuri:
 +* ca un subansamblu al altor pattern-uri:​
 + ** impreună cu pattern-urile Abstract Factory, Builder, Prototype etc. De exemplu, în aplicație dorim un singur obiect factory pentru a crea obiecte de un anumit tip.
 +* în locul variabilelor globale. Singleton este preferat variabilelor globale deoarece, printre altele, nu poluează namespace-ul global cu variabile care nu sunt necesare.
 +
 +Singleton este utilizat des în situații în care avem obiecte care trebuie accesate din mai multe locuri ale aplicației:​
 +* obiecte de tip logger
 +* obiecte care reprezintă resurse partajate (conexiuni, sockets etc.)
 +* obiecte ce conțin configurații pentru aplicație
 +* pentru obiecte de tip //​Factory//​.
 +
 +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]]
 +
 +Din punct de vedere al design-ului și testarii unei aplicații de multe ori se evită folosirea acestui pattern, în test-driven development fiind considerat un **//​anti-pattern//​**. A avea un obiect Singleton a carei referință o folosim peste tot prin aplicație introduce multe dependențe între clase și îngreunează testarea individuală a acestora. ​
 +
 +In general, codul care folosește stări globale este mai dificil de testat pentru că implică o cuplare mai strânsă a claselor, și împiedică izolarea unei componente și testarea ei individuală. Dacă o clasă testată folosește un obiect singleton, atunci trebuie testat și singleton-ul. Soluția este simularea //mock-up// a singleton-ului în teste. Încă o problemă a acestei cuplări mai strânse apare atunci când două teste depind unul de celălalt prin modificarea singleton-ului,​ deci trebuie impusă o anumită ordine a rulării testelor.
 +
 +<note tip>​Încercați să nu folosiți în exces metode statice și componente Singleton.</​note>​
 +
 +
 +=== Implementare ===
 +
 +Aplicarea pattern-ului Singleton constă în implementarea unei metode ce permite crearea unei noi instanțe a clasei dacă aceasta nu există, și întoarcerea unei referințe către aceasta dacă există deja. În Java, pentru a asigura o singură instanțiere a clasei, constructorul trebuie să fie //​private//,​ iar instanța să fie oferită printr-o metodă statică, publică.
 +
 +În cazul unei implementări Singleton, clasa respectivă va fi instanțiată **lazy** (//lazy instantiation//​),​ utilizând memoria doar în momentul în care acest lucru este necesar deoarece instanța se creează atunci când se apelează ''​getInstance()'',​ acest lucru putând fi un avantaj în unele cazuri, față de clasele non-singleton,​ pentru care se face //eager instantiation//,​ deci se alocă memorie încă de la început, chiar dacă instanța nu va fi folosită (mai multe detalii și exemplu în [[http://​www.javaworld.com/​article/​2077568/​learn-java/​java-tip-67--lazy-instantiation.html |acest articol]])
 +
 +<​imgcaption image_singleton|Diagrama de clase pentru Singleton>​{{ .:​design-patterns:​singletonclassdiagram.png |}}</​imgcaption>​
 +
 +
 +Respectând cerințele pentru un singleton enunțate mai sus, în Java, putem implementa o componentă de acest tip în mai multe feluri, inclusiv folosind ''​enum''​-uri în loc de clase. Atunci când îl implementâm trebuie avut în vedere contextul în care îl folosim, astfel încât să alegem o soluție care să funcționeze corect în toate situațiile ce pot apărea în aplicație (unele implementări au probleme atunci când sunt accesate din mai multe thread-uri sau când trebuie serializate).
 +
 +<code java>
 + ​public class Singleton {
 +
 +   ​private static Singleton instance = null;
 +   
 +   ​private Singleton() {}
 +   
 +   ​public static Singleton getInstance() {
 +      if(instance == null) {
 +          instance = new Singleton();​
 +      }
 +      return instance; ​     ​
 +   }
 +   ...
 + }
 +</​code>​
 +
 +  * Instanța ''​instance''​ este //private//
 +  * Constructorul este privat ca sa nu poata fi apelat decat din clasa respectivă
 +  * Instanța este inițial nulă
 +  * Instanța este creată la prima rulare a //​getInstance()//​
 +
 +//De ce Singleton și nu clase cu membri statici?//
 +
 +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 gasi [[http://​geekexplains.blogspot.ro/​2008/​06/​can-you-override-static-methods-in-java.html | aici]], și o comparatie între static și dynamic binding [[http://​geekexplains.blogspot.ro/​2008/​06/​dynamic-binding-vs-static-binding-in.html | aici]]).
  
  
Line 227: Line 295:
     * o constantă MAGIC_NUMBER având orice valoare doriți ​     * o constantă MAGIC_NUMBER având orice valoare doriți ​
     * un String constant MAGIC_STRING,​ lung de minim 20 de caractere, generat random     * un String constant MAGIC_STRING,​ lung de minim 20 de caractere, generat random
-    * un constructor care primește: un String numit ''​firstName'',​ un String numit ''​lastName''​ și un int numit ''​age'' ​+    * un constructor care primește: un String numit ''​name''​
     * o metodă ''​getPassword()''​ care va returna parola ​     * o metodă ''​getPassword()''​ care va returna parola ​
-      * Parola ​se construiește concatenand următoarele șiruri: ​ +      * parola ​se construiește concatenand următoarele șiruri:
-        * șirul format din ultimele ''​(age % 3)''​ litere din firstName+
         * un șir random de lungime MAGIC_NUMBER,​ generat cu ''​RandomStringGenerator''​ și cu un alfabet obținut din 10 caractere obținute random din MAGIC_STRING         * un șir random de lungime MAGIC_NUMBER,​ generat cu ''​RandomStringGenerator''​ și cu un alfabet obținut din 10 caractere obținute random din MAGIC_STRING
-        * și șirul format prin conversia la String a numărului (age + lungimea ​lui lastName).+        * și șirul format prin conversia la String a lungimii ​lui name + un numar intreg generat random din intervalul [0,100]
     * 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]]     * 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]]
-  - (**3p**) ​Modificati ​implementarea clasei PasswordMaker astfel ​incat +  - (**3p**) ​Modificați ​implementarea clasei PasswordMaker astfel ​încât să respecte conceptul de **Singleton pattern** (să permită instanțierea ​unei singur obiect) 
-    * Sa respecte conceptul de Singleton pattern (sa permita instantierea ​unei singur obiect) +        * Pornind de la exemplul de Singleton ​din textul laboratorului implementați o versiune care urmează principiul ​de Eager Initialization (singura ​instanța ​a clasei este creată ​la pornirea ​aplicației, indiferent ​dacă este necesar sau nu) 
-        * Implementati ​Singleton ​pattern folosind conceptul ​de Eager Initialization (singura ​instanta ​a clasei este creata ​la pornirea ​aplicatiei, indiferent ​daca este necesar sau nu) +        * Implementați o versiune ​de Singleton în care variabila ''​instance'' ​este inițializata într-un bloc static 
-        * Modificati implementarea anterioara urmand conceptul ​de Lazy Initialization (singura instanta a clasei este creata doar atunci cand este nevoie de ea+        * Adăugați un contor care să numere de câte ori a fost accesată metodă ''​getInstance()''​. E nevoie ​ca acest contor să fie static? 
-  - (**3p**) Să se implementeze o clasă ''​MyImmutableArray''​ care sa contina+        * //​Tema ​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ă? 
-    * un field de ''​ArrayList<​Integer>​ immutableArray;''​ neinitializat ​in prima faza +  - (**3p**) Să se implementeze o clasă ''​MyImmutableArray''​ care să conțină
-    * un constructor care primeste ​un ArrayList<​Integer> ​si copiaza ​toate elementele din acel array in ''​immutableArray''​ +    * un field de ''​ArrayList<​Integer>​ immutableArray;''​ neinitializat ​în primă ​faza 
-    * o metoda ​getArray ​implementata in asa fel incat field-ul ''​immutableArray'' ​sa ramana ​immutable +    * un constructor care primește ​un ArrayList<​Integer> ​și copiază ​toate elementele din acel array în ''​immutableArray''​ 
-  - (**1p**) ​Testati ​clasa ''​MyImmutableArray'' ​demonstrand ​faptul ​ca instantele ​acestei clase sunt imutabile+    * o metodă ​getArray ​implementată în așa fel încât ​field-ul ''​immutableArray'' ​să rămână ​immutable 
 +  - (**1p**) ​Testați ​clasa ''​MyImmutableArray'' ​demonstrând ​faptul ​că instanțele ​acestei clase sunt imutabile 
 +== Resurse == 
 +* {{:​laboratoare:​static-final:​schelet_lab4.zip|Arhiva zip cu clasa RandomStringGenerator.java}}
  
laboratoare/static-final.1571507889.txt.gz · Last modified: 2019/10/19 20:58 by Adriana Draghici