User Tools

Site Tools


Problem constructing authldap
laboratoare:agregare-mostenire
Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
laboratoare:agregare-mostenire [2018/10/13 11:44]
Laurentiu Stamate comentarii în română la exemplele de cod
laboratoare:agregare-mostenire [2019/10/30 01:02] (current)
Florin Mihalache [Resurse]
Line 47: Line 47:
  
 class Book { class Book {
-    private String title; // Compoziţie +    private String title; // Compunere 
-    private Page[] pages; // Compoziţie+    private Page[] pages; // Compunere
     private LibraryRow libraryRow = null; // Agregare     private LibraryRow libraryRow = null; // Agregare
   
Line 223: Line 223:
 ===Să încercăm să evităm folosirea instanceof=== ===Să încercăm să evităm folosirea instanceof===
  
-Totuși, deși v-am ilustrstat ​cum ''​instanceof''​ ne poate ajuta să ne dăm seama la ce să facem **downcasting**,​ este de preferat să ne organizăm clasele și designul codului în așa fel încât să lăsăm limbajul Java să facă automat verificarea tipului și să cheme metoda corespunzătoare. Vom refactororiza codul anterior pentru a nu fi nevoie de ''​instanceof'':​+Totuși, deși v-am ilustrat ​cum ''​instanceof''​ ne poate ajuta să ne dăm seama la ce să facem **downcasting**,​ este de preferat să ne organizăm clasele și designul codului în așa fel încât să lăsăm limbajul Java să facă automat verificarea tipului și să cheme metoda corespunzătoare. Vom refactororiza codul anterior pentru a nu fi nevoie de ''​instanceof'':​
  
 <code java5> <code java5>
Line 291: Line 291:
 Constructorii **nu** se moștenesc și pot fi apelați doar în contextul unui constructor copil. Apelurile de constructor sunt înlănțuite,​ ceea ce înseamnă că înainte de a se inițializa obiectul copil, mai întâi se va inițializa obiectul părinte. În cazul în care părintele este copil la rândul lui, se va înițializa părintele lui (până se va ajunge la parintele suprem -- root). Constructorii **nu** se moștenesc și pot fi apelați doar în contextul unui constructor copil. Apelurile de constructor sunt înlănțuite,​ ceea ce înseamnă că înainte de a se inițializa obiectul copil, mai întâi se va inițializa obiectul părinte. În cazul în care părintele este copil la rândul lui, se va înițializa părintele lui (până se va ajunge la parintele suprem -- root).
  
-În laboratorul [[http://​elf.cs.pub.ro/​poo/​laboratoare/​constructori-referinte#​cuvantul-cheie-final--obiecte-immutable |Constructori și referințe]] au fost prezentate și câteva din cuvintele cheie ce pot fi puse înaintea unor membri ai claselor, sau chiar a claselor. 
- 
-* cuvântul cheie **''​final''​** ​ 
-    * folosit la declararea unei metode, implicând faptul că metoda nu poate fi suprascrisă în clasele derivate ​ 
-    * folosit la declararea unei clase, implicând faptul că acea clasă nu poate fi derivată ​ (de exemplu clasa [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​String.html | String]]) 
-  ​ 
 Pe lângă reutilizarea codului, moștenirea dă posibilitatea de a dezvolta pas cu pas o aplicație (procedeul poartă numele de //​incremental development//​). Astfel, putem folosi un cod deja funcțional și adaugă alt cod nou la acesta, în felul acesta izolându-se bug-urile în codul nou adăugat. Pentru mai multe informații citiți capitolul //Reusing Classes// din cartea //Thinking în Java (Bruce Eckel)// ​ Pe lângă reutilizarea codului, moștenirea dă posibilitatea de a dezvolta pas cu pas o aplicație (procedeul poartă numele de //​incremental development//​). Astfel, putem folosi un cod deja funcțional și adaugă alt cod nou la acesta, în felul acesta izolându-se bug-urile în codul nou adăugat. Pentru mai multe informații citiți capitolul //Reusing Classes// din cartea //Thinking în Java (Bruce Eckel)// ​
  
Line 368: Line 362:
  
 <note warning>​Sintaxa Java permite apelarea metodelor statice pe instanțe (e.g. a.print în loc de Car.print), dar acest lucru este considerat bad practice pentru că poate îngreuna înțelegerea codului.</​note>​ <note warning>​Sintaxa Java permite apelarea metodelor statice pe instanțe (e.g. a.print în loc de Car.print), dar acest lucru este considerat bad practice pentru că poate îngreuna înțelegerea codului.</​note>​
 +
 +===Suprascrierea corecta a metodei equals(Object o)===
 +
 +Una din problemele cele mai des întâlnite este suprascrierea corectă a metodei //equals//. Mai jos putem vedea un exemplu de suprascriere incorectă a acestei metode.
 +
 +<code java>
 +public class Car {
 +    public boolean equals(Car c) {
 +        System.out.println("​Car"​);​
 +        return true;
 +    }
 +    ​
 +    public boolean equals(Object o) {
 +        System.out.println("​Object"​);​
 +        return false;
 +    }
 +}
 +</​code>​
 +
 +Prima metodă este o **supraîncărcare** a metodei equals iar a doua metodă este **suprascrierea** metodei equals.
 +
 +<code java>
 +Car a = new Car();
 +Dacia b = new Dacia();
 +Int c = new Int(10);
 +
 +a.equals(a);​ // afișează Car
 +a.equals(b);​ // afișează Car deoarece se face upcasting de la Dacia la Car
 +a.equals(c);​ // afișează Object deoarece se face upcasting de la Int la Object
 +</​code>​
 +
 +Problema care se poate observa este că putem pasa ca argumente metodei equals si tipuri de date diferite de ''​Car'',​ lucru ce ar putea arunca excepții de cast sau când vrem să accesăm anumite proprietăți din instanță. Mai jos este modul corect de suprascrie metoda equals.
 +
 +<code java>
 +public class Car {
 +    public boolean equals(Car c)
 +    {
 +        return true;
 +    }
 +
 +    public boolean equals(Object o)
 +    {
 +        if (o == this) {
 +            return true;
 +        }
 +
 +        if (!(o instanceof Car)) {
 +            return false;
 +        }
 +
 +        return equals((Car) o);
 +    }
 +}
 +</​code>​
 +
 +De reținut că folosirea ''​instanceof''​ nu este recomandată,​ însă în acest caz este singurul mod prin care ne putem asigura ca instanța de obiect trimisă metodei este de tip ''​Car''​.
  
 ==Cuvântul cheie super. Întrebuințări== ==Cuvântul cheie super. Întrebuințări==
Line 454: Line 504:
 <note important>​Chiar dacă nu se specifică apelul metodei ''​super()'',​ compilatorul va apela automat constructor-ul implicit al părintelui însă dacă se dorește apelarea altui constructor,​ apelul de ''​super(args)''​ respectiv este obligatoriu</​note>​ <note important>​Chiar dacă nu se specifică apelul metodei ''​super()'',​ compilatorul va apela automat constructor-ul implicit al părintelui însă dacă se dorește apelarea altui constructor,​ apelul de ''​super(args)''​ respectiv este obligatoriu</​note>​
   ​   ​
 +==Summary==
 +**Relații între obiecte:**
 +  * Agregare - **has a**
 +  * Moștenire - **is a**
 +
 +**Upcasting** ​
 +  * convertire **copil** => **parinte**
 +  * realizată automat
 +
 +**Downcasting**
 +  * convertire **parinte** =>​**copil**
 +  * trebuie facută explicit de către programator
 +  * încercați să evitați folosirea operatorului **instanceof**
 +
 +**Suprascrierea** ​
 +  * înlocuirea functionalitații metodei din clasa de bază în clasa derivată
 +  * pastreaza numele și semnatura metodei
 +
 +**Supraincarcarea**  ​
 +  * în interiorul clasei pot exista mai multe metode cu acelasi nume, cu condiția ca semnătura (tipul, argumentele) să fie diferită
 +
 +**super**
 +  * instanța clasei parinte
 +  * amintiți-vă din laboratorul anterior că **[[[[laboratoare:​constructori-referinte|this]]** se referă la instanța clasei curente
 +
 +
 ==Exerciții== ==Exerciții==
  
-<note important>​Exercițiile 1-5 se rezolvă ​în ordine</​note>​+Gigel vrea să-i faca mamei sale un cadou de ziua ei și știe că-i plac foarte mult bomboanele. El are nevoie de ajutorul vostru pentru a construi cel mai frumos și gustos cadou: 
 +   
 +**Task 1** [2p] 
 + 
 +Veti proiecta o clasa ''​CandyBox'',​ care va conține câmpurile private ''​flavor''​ (String) și ''​origin''​ (String). Clasa va avea, de asemenea: 
 +                  * un constructor fără parametri 
 +                  * un constructor ce va inițializa toate campurile 
 +                  * o metoda de tip float ''​getVolume()'',​ care va intoarce valoarea 0; 
 +                  * Întrucât clasa ''​Object''​ se află în rădăcina arborelui de moștenire pentru orice clasă, orice instanta va avea acces la o serie de facilități oferite de Object. Una dintre ele este metoda ''​toString()'',​ al cărei scop este de a oferi o reprezentare unei instanțe sub forma unui șir de  caractere, utilizata in momentul apelului System.out.println(). Adaugati o metoda ''​toString()'',​ care va returna flavor-ul si regiunea de proveniență a cutiei de bomboane. 
 + 
 +**Task 2** [2p] 
 + 
 +Din ea derivați clasele ''​Lindt'',​ ''​Baravelli'',​ ''​ChocAmor''​. Pentru un design interesant, cutiile vor avea forme diferite: 
 +  * //Lindt// va contine ''​length'',​ ''​width'',​ ''​height''​ (float); 
 +  * //​Baravelli//​ va fi un cilindru. Acesta va conține un camp ''​radius''​ și unul ''​height''​ (float); 
 +  * //​ChocAmor//,​ fiind un cub, va conține un camp ''​length''​ (float); 
 + 
 +Clasele vor avea: 
 +  * constructori fără parametri 
 +  * constructori care permit inițializarea membrilor. Identificați o modalitate de reutilizare a codului existent. Pentru fiecare tip de cutie veti initializa, in constructor,​ campurile ''​flavor''​ și ''​origin''​ cu tipul corespunzator 
 +  * Suprascrieti metoda //​getVolume()//​ pentru a intoarce volumul specific fiecarei cutii de bomboane, in functie de tipul sau. 
 +  * Suprascrieti ​ metoda //​toString()//​ în clasele derivate, astfel încat aceasta să utilizeze implementarea metodei toString() din clasa de bază. Returnați un mesaj de forma //"The " + origin + " " + flavor + " has volume " + volume//; 
 + 
 +**Task 3** [1p] 
 +  
 + 
 +Adăugați o metodă ''​equals()''​ în clasa ''​CandyBox''​. Justificați criteriul de echivalentă ales. Vedeți metodele clasei [[https://​docs.oracle.com/​en/​java/​javase/​12/​docs/​api/​java.base/​java/​lang/​Object.html | Object]], moștenită de toate clasele - Object are metoda equals, a cărei implementare verifică echivalența obiectelor comparând referințele. 
 +<note important>​**Hint:** 
 +Puteti genera automat metoda, cu ajutorul IDE. Selectați câmpurile considerate și 
 +analizați ​în ce fel va fi suprascrisă metoda equals.</​note>​ 
 + 
 +**Task 4** - //''​Upcasting''//​ [2p] 
 + 
 +Acum că am stabilit tipul cutiilor de bomboane, putem construi cadoul, ramanand la latitudinea vostra care va fi designul lui. In pachetul java.util se gaseste clasa ''​ArrayList'',​ care definește un resizable array, cu metodele specifice (add, size, get, lista lor completa este in [[https://​docs.oracle.com/​en/​java/​javase/​12/​docs/​api/​java.base/​java/​util/​ArrayList.html|documentatie]]). Creati o clasă ''​CandyBag'',​ care va conține un ArrayList cu mai multe cutii din fiecare tip. Creați obiecte de tip Lindt si testați egalitatea lor; 
  
-  - (**2p**) Întrucât în ierarhia de clase Java, clasa ''​Object''​ se află în rădăcina arborelui de moștenire pentru orice clasă, orice clasă va avea acces la o serie de facilități oferite de ''​Object''​. Una dintre ele este metoda ''​toString()'',​ al cărei scop este de a oferi o reprezentare a unei instanțe de clasă sub forma unui șir de caractere.  +**Task 5** - //''​Downcasting''// ​[1p]
-    * Definiți clasa **''​Form''​** cu un membru ''​color''​ de tip ''​String'',​ o metoda ''​getArea()''​ care pentru început va intoarce 0 și o metodă ''​toString()''​ care va returna acestă culoare.  +
-    * Clasa va avea, de asemenea:  +
-      * un constructor fără parametri  +
-      * un constructor ce va inițializa culoarea.  +
-    * Din ea derivați clasele **''​Triangle''​** și **''​Circle''​**:​  +
-      * Clasa ''​Triangle''​ va avea 2 membri ''​height''​ si ''​base''​ de tip ''​float''​.  +
-      * Clasa ''​Circle''​ va avea membrul ''​radius''​ de tip ''​float''​.  +
-      * Clasele vor avea:  +
-        * constructori fără parametri  +
-        * constructori care permit inițializarea membrilor. Identificați o modalitate de **reutilizare** a codului existent.  +
-    * Instanțiati clasele ''​Triangle''​ și ''​Circle'',​ și apelați metoda ''​toString()''​ pentru fiecare instanță. +
-    * suprascrieti metoda ''​getArea()''​ pentru a intoarce aria specifica figuri geometrice. +
-  ​(**2p**) Adăugați metode ​''​toString()'' ​în cele două clase derivate, care să returneze tipul obiectului, culoarea si aria. De exemplu: ​  +
-      * pentru clasa ''​Triangle'',​ se va afișa: "​Triunghi:​ rosu 10"  +
-      * pentru clasa ''​Circle'',​ se va afișa: "Cerc: verde 12.56"​ +
-      * Modificați implementarea ''​toString()''​ din clasele derivate astfel încât aceasta să utilizeze implementarea metodei ''​toString()''​ din clasa de bază.  +
-  - (**1p**) Adăugați o metodă ''​equals''​ în clasa ''​Triangle''​. Justificați criteriul de echivalentă ales.  +
-    * Hint: vedeți metodele clasei [[http://docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​Object.html | Object]], moștenită de toate clasele - Object are metoda ''​equals'',​ a cărei implementare verifică echivalența obiectelor comparând referințele. +
-  - (**1p**) Upcasting.  +
-    * Creați un vector de obiecte ''​Form''​ și populați-l cu obiecte de tip ''​Triangle''​ și ''​Circle''​ (upcasting).  +
-    * Parcurgeți acest vector și apelați metoda ''​toString()''​ pentru elementele sale. Ce observați?  +
-  - (**2p**) Downcasting.  +
-    * Adăugați clasei ''​Triangle''​ metoda ''​printTriangleDimensions''​ și clasei ''​Circle''​ metoda ''​printCircleDimensions''​. Implementarea metodelor constă în afișarea bazei si inaltimii respectiv razei.  +
-    * Parcurgeți vectorul de la exercițiul anterior și, folosind downcasting la clasa corespunzătoare,​ apelați metodele specifice fiecărei clase (''​printTriangleDimensions''​ pentru ''​Triangle''​ și ''​printCircleDimensions''​ pentru ''​Circle''​). Pentru a stabili tipul obiectului curent folosiți operatorul **''​instanceof''​**.  +
-    * Modificați programul anterior astfel încât downcast-ul să se facă mereu la clasa ''​Triangle''​. Ce observați?  +
-    * Modificați programul anterior astfel încât să nu mai aveți nevoie de ''​instanceof''​ deloc.+
  
-<note important>​Exercițiul 6 este independent de cele de mai sus</​note>​+Adaugati clasei ''​Baravelli'',​ functia ''​printBaravelliDim()'',​ care va afișa dimensiunile razei și inaltimii. În mod analog, procedati cu celelalte tipuri de cutii, adaugand metodele ''​printChocAmorDim()''​ si ''​printLindtDim()'',​ în care să afișați dimensiunile fiecarei cutii.
  
-  - (**1.5p + 1.5p**) Implementați două clase ''​QueueAggregation''​ și ''​QueueInheritance''​ pe baza clasei ''​{{:​laboratoare:​agregare-mostenire:​array.zip | Array}}''​ furnizate de noi, utilizând, pe rând, ambele abordări: **moștenire** și **agregare**. Precizări:  +**Task 6** - //''​Agregare''​// [2p]
-    * Coada va conține elemente de tip ''​int''​.  +
-    * Clasele ''​QueueAggregation''​ și ''​QueueInheritance''​ trebuie să ofere metodele ''​enqueue''​ și ''​dequeue'',​ specifice acestei structuri de date.  +
-    * Clasa ''​Array''​ reprezintă un wrapper pentru lucrul cu vectori. Metoda ''​get(pos)''​ întoarce valoarea din vector de la poziția ''​pos'',​ în timp ce metoda ''​set(pos,​ val)''​ atribuie poziției ''​pos''​ din vector valoarea ''​val''​. Noutatea constă în verificarea poziției furnizate. În cazul în care aceasta nu se încadrează în intervalul valid de indici, ambele metode întorc constanta ''​ERROR''​ definită în clasa.  +
-    * Metoda ''​main''​ definită în clasa ''​Array''​ conține exemple de utilizare a acestei clase. Experimentați!  +
-    * Metoda ''​enqueue''​ va oferi posibilitatea introducerii unui număr întreg în capătul cozii (dacă aceasta nu este deja plină), în timp ce metoda ''​dequeue''​ va înlătura elementul din vârful cozii și îl va întoarce (dacă coada nu este goală). În caz de insucces (coada plină la ''​enqueue'',​ respectiv goală la ''​dequeue''​),​ ambele metode vor întoarce constanta ''​ERROR''​. +
-    * Ce problemă poate apărea din cauza constantei ''​ERROR''?​ (Hint: Dacă în coadă am un element egal cu valoarea constantei ''​ERROR''?​) Gândiți-vă la o rezolvare. +
-    * Ce puteți spune despre vizibilitatea metodelor ''​get''​ și ''​set'',​ în clasele ''​QueueAggregation''​ și ''​QueueInheritance''​, în varianta ce utilizează moștenire? Ce problemă indică răspunsul? Furnizați o soluție la această problemă. ​+
  
 +Gigel va vrea sa trimită prin curier cadoul, pentru a nu-l gasi mama lui mai devreme. Ajutați-l să determine locația, creând clasa  "​Area",​ care va conține un obiect de tip ''​CandyBag'',​ un camp "​number"​ (int) și un câmp "​street"​ (String)
 +Clasa va avea, de asemenea:
 +  * un constructor fără parametri
 +  * un constructor ce va inițializa toate campurile ​
 +  * Acum ca am finalizat construcția,​ îi vom oferi mamei informații despre cadoul ei printr-o felicitare. Creați o metoda ''​getBirthdayCard()'',​ care va afișa, pe primul rand, adresa completă, iar apoi un mesaj de ''​la multi ani''​. ​
 +  * Tot aici, parcurgeți array-ul, apeland metoda ''​toString()''​ pentru elementele sale.
 +  * Parcurgeți array-ul și, folosind downcasting la clasa corespunzătoare,​ apelați metodele specifice fiecărei clase. Pentru a stabili tipul obiectului curent folosiți operatorul ''​instanceof''​
 +  * In final, modificați cum considerati programul anterior astfel încât să nu mai aveți nevoie de instanceof.
  
 == Resurse == == Resurse ==
-* {{:laboratoare:​agregare-mostenire:​array.zip|Arhiva zip cu clasa Array.java}} +* {{laboratoare:​agregare-mostenire:​lab3-sol-2019.zip|Soluție}} 
-<​html><​a class="​media mediafile mf_pdf"​ href="?​do=export_pdf">​PDF laborator</​a></​html>​+[[laboratoare:​old-exercises|Exerciții din alți ani]]
  
 == Referințe == == Referințe ==
laboratoare/agregare-mostenire.1539420244.txt.gz · Last modified: 2018/10/13 11:44 by Laurentiu Stamate