This shows you the differences between two versions of the page.
|
poo-ca-cd:laboratoare:abstractizare-clase-speciale-si-restrictii [2025/10/27 01:04] florian_luis.micu [Clase și metode abstracte] |
poo-ca-cd:laboratoare:abstractizare-clase-speciale-si-restrictii [2025/11/12 11:31] (current) florian_luis.micu [Clase și metode abstracte] |
||
|---|---|---|---|
| Line 3: | Line 3: | ||
| * Autori: [[miculuis1@gmail.com | Florian-Luis Micu ]], [[sorinabuf@gmail.com | Sorina-Anamaria Buf ]], [[stefancocioran@gmail.com | Ștefan Cocioran ]] | * Autori: [[miculuis1@gmail.com | Florian-Luis Micu ]], [[sorinabuf@gmail.com | Sorina-Anamaria Buf ]], [[stefancocioran@gmail.com | Ștefan Cocioran ]] | ||
| * Data publicării: 27.10.2025 | * Data publicării: 27.10.2025 | ||
| - | * Data ultimei modificări: 27.10.2025 | + | * Data ultimei modificări: 04.11.2025 |
| + | * clarificări și expandarea conținutului despre DTO-uri. | ||
| + | * ștergerea notiței legată de contest (numele problemei a fost actualizat pe Code Devmind). | ||
| =====Obiective===== | =====Obiective===== | ||
| Line 148: | Line 151: | ||
| <code java> | <code java> | ||
| - | Vehicle vehicle = new Sedan(); | + | Sedan sedan = new Sedan(); |
| - | vehicle.startEngine(); // Output: Car engine started! | + | sedan.startEngine(); // Output: Car engine started! |
| - | vehicle.openTrunk(); // Output: Trunk opened in the back of the car! | + | sedan.openTrunk(); // Output: Trunk opened in the back of the car! |
| </code> | </code> | ||
| Line 197: | Line 200: | ||
| ====Interfețe==== | ====Interfețe==== | ||
| - | Interfețele oferă un mecanism prin care putem defini **comportamente** fără a impune moștenire de implementare. Ele stabilesc un contract pe care orice clasă îl poate îndeplini, indiferent din ce parte a ierarhiei de clase provine. | + | Interfețele oferă un mecanism prin care putem defini **comportamente** fără a forța clasele să moștenească implementarea. Ele stabilesc un contract pe care orice clasă îl poate îndeplini, indiferent din ce parte a ierarhiei de clase provine. |
| ===Ce este o interfață?=== | ===Ce este o interfață?=== | ||
| Line 271: | Line 274: | ||
| ===Iniţializarea câmpurilor în interfeţe=== | ===Iniţializarea câmpurilor în interfeţe=== | ||
| - | În interfețe toate câmpurile sunt implicit ''public static final''. Nu pot exista **blank final**s (câmpuri finale neinițializate), dar pot exista constante non-primitive dacă sunt inițializate la declarație. | + | În interfețe toate câmpurile sunt implicit ''public static final''. Nu pot exista **blank finals** (câmpuri finale neinițializate), dar pot exista **constante non-primitive** dacă sunt inițializate la declarație. |
| <code java> | <code java> | ||
| Line 281: | Line 284: | ||
| ===Interfețele ca tipuri=== | ===Interfețele ca tipuri=== | ||
| - | După ce definim o interfață, ea devine un tip de referință în Java, la fel ca o clasă. Asta înseamnă că putem: | + | După ce definim o interfață, ea devine un **tip de referință** în Java, la fel ca o clasă. Asta înseamnă că putem: |
| * Declara variabile de tipul interfeței | * Declara variabile de tipul interfeței | ||
| * Folosi interfața ca tip pentru parametrii unor metode | * Folosi interfața ca tip pentru parametrii unor metode | ||
| * Specifica interfața ca tip de return al unei metode | * Specifica interfața ca tip de return al unei metode | ||
| - | Astfel, orice obiect care implementează interfața poate fi atribuit unei variabile de acel tip, indiferent de clasa sa concretă. | + | Astfel, orice obiect care implementează interfața poate fi atribuit unei variabile de acel tip, indiferent de clasa sa concretă (upcasting). |
| <code java> | <code java> | ||
| Line 334: | Line 337: | ||
| ===Moștenire multiplă=== | ===Moștenire multiplă=== | ||
| - | În Java, o interfață poate moșteni mai multe interfețe folosind keyword-ul extends. Aceasta permite combinarea comportamentelor din mai multe surse fără a fi nevoie de moștenire multiplă de clase (care nu este permisă în Java). | + | În Java, **o interfață** poate moșteni **mai multe interfețe** folosind keyword-ul ''extends''. Acesta permite combinarea comportamentelor din mai multe surse fără a fi nevoie de moștenire multiplă de clase (care nu este permisă în Java). |
| <code java> | <code java> | ||
| Line 357: | Line 360: | ||
| </code> | </code> | ||
| - | Totodată, o clasă poate moșteni mai multe interfețe folosind keyword-ul ''implements'': | + | Totodată, **o clasă** poate moșteni **mai multe interfețe** folosind keyword-ul ''implements'': |
| <code java> | <code java> | ||
| Line 412: | Line 415: | ||
| </code> | </code> | ||
| - | <note tip>Situația de mai sus **nu** reprezintă //Problema diamantului//, deoarece chiar dacă se pot moșteni mai multe interfețe, acestea nu au un corp, deci implementarea este lăsată la latitudinea clasei care le va implementa.</note> | + | <note tip>Situația de mai sus **nu** se încadrează la //Problema diamantului//, deoarece chiar dacă se pot moșteni mai multe interfețe, acestea nu au un corp, deci implementarea este lăsată la latitudinea clasei care le va implementa.</note> |
| <spoiler [Optional] Metode default în interfețe și Problema diamantului> | <spoiler [Optional] Metode default în interfețe și Problema diamantului> | ||
| **Metode default în interfețe** | **Metode default în interfețe** | ||
| - | În Java (de la Java 8), interfețele pot avea metode cu implementare folosind cuvântul cheie ''default''. | + | În Java (de la Java 8), interfețele pot avea **metode cu implementare** folosind cuvântul cheie ''default''. |
| Scopul lor: | Scopul lor: | ||
| Line 479: | Line 482: | ||
| ====Clase abstracte vs. Interfețe==== | ====Clase abstracte vs. Interfețe==== | ||
| - | După cum se poate observa, atât clasele abstracte cât și interfețele oferă avantaje similare. Pentru a observa asemănările și diferențele dintre acestea am creat următorul tabel: | + | După cum se poate observa, atât clasele abstracte cât și interfețele oferă avantaje similare. Să observăm următorul tabel pentru o comparație directă: |
| ^ Caracteristică ^ Clasă abstractă ^ Interfață ^ | ^ Caracteristică ^ Clasă abstractă ^ Interfață ^ | ||
| Line 494: | Line 497: | ||
| ====Exemplu ierarhie de clase==== | ====Exemplu ierarhie de clase==== | ||
| - | Proiectele voastre ar trebui să conțină o combinație între clase abstracte și interfețe. | + | Un proiect complex ar trebui să conțină o **combinație** între clase abstracte și interfețe. |
| - | Să presupunem următoarea ierarhie de clase. | + | Să presupunem următoarea ierarhie de clase: |
| {{:poo-ca-cd:laboratoare:abstractizare-clase-speciale-si-restrictii:inheritance_example.png?nolink&600|}} | {{:poo-ca-cd:laboratoare:abstractizare-clase-speciale-si-restrictii:inheritance_example.png?nolink&600|}} | ||
| Line 539: | Line 542: | ||
| } | } | ||
| </code> | </code> | ||
| + | |||
| + | <note tip> | ||
| + | Conform laboratoarelor trecute, vă reamintim că puteți crea de asemenea și **constante globale** dacă faceți un câmp ''static final''. | ||
| + | </note> | ||
| De asemenea, putem marca **parametrii** unei metode ca fiind ''final'' pentru a indica faptul că aceștia **nu pot fi schimbați în corpul unei metode**: | De asemenea, putem marca **parametrii** unei metode ca fiind ''final'' pentru a indica faptul că aceștia **nu pot fi schimbați în corpul unei metode**: | ||
| Line 654: | Line 661: | ||
| ====Enums==== | ====Enums==== | ||
| - | Enums sunt tipuri speciale de clasă care definesc un set fix de constante. Ele oferă o modalitate sigură și lizibilă de a reprezenta valori finite și constante într-un program. | + | Enums sunt tipuri speciale de clasă care definesc un **set fix de constante**. Ele oferă o modalitate **sigură** și **lizibilă** de a reprezenta **valori finite** și **constante** într-un program. |
| Exemplu simplu: | Exemplu simplu: | ||
| Line 762: | Line 769: | ||
| ===Avantaje ale folosirii Enum=== | ===Avantaje ale folosirii Enum=== | ||
| - | * Cod mai clar și mai lizibil comparativ cu constantele int sau String. | + | * Cod mai clar și mai lizibil comparativ cu constantele de tip ''int'' sau ''String''. |
| - | * Siguranță la compilare: nu poți atribui valori invalide. | + | * Siguranță la compilare, deoarece nu putem atribui valori invalide. |
| - | * Poți adăuga metode și comportamente specifice fiecărei constante. | + | * Putem adăuga metode și comportamente specifice fiecărei constante. |
| * Se integrează bine cu switch/case pentru decizii pe valori finite. | * Se integrează bine cu switch/case pentru decizii pe valori finite. | ||
| <note tip> | <note tip> | ||
| - | Puteți folosi în continuare câmpuri de tipul ''static final'' într-o clasă normală care are rol de a ține constante, însă este de preferat să folosiți Enum-uri fiind o alternativă mai modernă. | + | Puteți folosi în continuare câmpuri de tipul ''static final'' într-o clasă normală care are rol de a ține constante, însă este de **preferat** să folosiți Enum-uri fiind o alternativă mai modernă cu toate avantajele de mai sus. |
| </note> | </note> | ||
| Line 828: | Line 835: | ||
| <note tip> | <note tip> | ||
| - | Observă că getteri există, dar nu se numesc ''getName()'', ci exact ca proprietatea: ''name()''. | + | Observați că getteri există, dar nu se numesc ''getName()'', ci exact ca proprietatea definită în clasă (ex. ''name()''). |
| </note> | </note> | ||
| Line 889: | Line 896: | ||
| <note tip> | <note tip> | ||
| - | * DTO (Data Transfer Object) este un obiect folosit pentru **transportul datelor** între straturi ale unei aplicații sau între aplicații diferite, **fără logică de business**. De exemplu, dacă am vrea să transmitem tot obiectul ''User'' dintr-o aplicație bancară am putea transmite inclusiv date confidențiale despre acesta (CNP, adresă etc.). Pentru a transmite doar datele necesare, putem crea o clasă ''UserDTO'' care conține doar câmpurile relevante pentru transfer. | + | Veți învăța despre **Spring** când veți face web back-end development. |
| - | * Veți învăța despre **Spring** când veți face web back-end development. | + | </note> |
| + | |||
| + | ===Ce sunt DTO-urile?=== | ||
| + | |||
| + | **DTO (Data Transfer Object)** este un obiect folosit pentru a **transfera** date între diferite părți ale unei aplicații sau între aplicații, **fără a conține logică de business**. Scopul lui este să transporte doar informațiile necesare, într-o formă **sigură** și **optimă**. | ||
| + | |||
| + | De exemplu, într-o aplicație bancară avem clasa User, care ar putea conține informații sensibile precum: | ||
| + | * nume | ||
| + | |||
| + | * CNP | ||
| + | * adresă | ||
| + | * sold cont | ||
| + | * roluri etc. | ||
| + | |||
| + | Dacă vrem să trimitem date despre utilizator către interfața web sau către alt serviciu, nu vrem să expunem date confidențiale precum CNP-ul sau adresa completă. În acest caz, creăm un ''UserDTO'', o clasă separată care conține **doar** informațiile necesare transferului, de exemplu: | ||
| + | |||
| + | <code java UserDTO.java> | ||
| + | public class UserDTO { | ||
| + | private String name; | ||
| + | private String email; | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Astfel: | ||
| + | * Protejăm datele sensibile | ||
| + | * Controlăm ce date sunt trimise | ||
| + | * Simplificăm transferul de date | ||
| + | * Evităm expunerea logicii interne a aplicației | ||
| + | |||
| + | ==Conversia dintr-o clasă în DTO== | ||
| + | |||
| + | Ca să convertim un obiect dintr-o clasă normală (**model/entity**) într-un **DTO**, există mai multe abordări. În principiu luăm doar câmpurile de care avem nevoie și le copiem în obiectul DTO. | ||
| + | |||
| + | Există mai multe metode pentru a face această copiere, însă cea recomandată este prin folosirea unui constructor: | ||
| + | |||
| + | <code java> | ||
| + | public class UserDTO { | ||
| + | private String name; | ||
| + | private String email; | ||
| + | |||
| + | public UserDTO(User user) { | ||
| + | this.name = user.getName(); | ||
| + | this.email = user.getEmail(); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Totodată, puteți rescrie codul de mai sus folosind ''record'' astfel: | ||
| + | |||
| + | <code java> | ||
| + | public record UserDTO(String name, String email) {} | ||
| + | </code> | ||
| + | |||
| + | <note tip> | ||
| + | * Când veți începe să lucrați cu framework-ul **Spring/Spring Boot**, veți întâlni termenii **model** sau **entity**, care reprezintă de obicei **obiectele stocate în baza de date**. Pentru moment este suficient să rețineți că aceste clase descriu obiecte reale din aplicație, cu **atribute** și **comportament**. | ||
| + | * În laboratoarele următoare vom învăța despre **Builder**, fiind un alt concept care ne poate ajuta în crearea DTO-urilor. | ||
| </note> | </note> | ||
| Line 946: | Line 1008: | ||
| * Exercițiile vor fi făcute pe platforma [[https://code.devmind.ro/|Devmind Code]]. Găsiți exercițiile din acest laborator în **contestul aferent**. | * Exercițiile vor fi făcute pe platforma [[https://code.devmind.ro/|Devmind Code]]. Găsiți exercițiile din acest laborator în **contestul aferent**. | ||
| * Vă recomandăm să copiați scheletul și să faceți exercițiile **mai întâi** în IntelliJ, deoarece acolo aveți acces la o serie de **instrumente** specifice unui IDE. După ce ați terminat exercițiile puteți să le **copiați** pe Devmind Code. | * Vă recomandăm să copiați scheletul și să faceți exercițiile **mai întâi** în IntelliJ, deoarece acolo aveți acces la o serie de **instrumente** specifice unui IDE. După ce ați terminat exercițiile puteți să le **copiați** pe Devmind Code. | ||
| + | </note> | ||
| + | |||
| + | <note note> | ||
| + | În contest veți observa că problema se cheamă //Problem-LAB05-POO//, însă nu este o problemă. Vom redenumi problema cât de curând. | ||
| </note> | </note> | ||
| Line 955: | Line 1021: | ||
| * Un task (''CounterOutTask.java'') care incrementeaza un contor global și afișează valoarea contorului după fiecare incrementare. | * Un task (''CounterOutTask.java'') care incrementeaza un contor global și afișează valoarea contorului după fiecare incrementare. | ||
| - | <note>**Notă**: Acesta este un exemplu simplu pentru [[http://en.wikipedia.org/wiki/Command_pattern|Command Pattern]]</note> | + | <note>**Notă**: Acesta este un exemplu simplu pentru Design Pattern-ul [[http://en.wikipedia.org/wiki/Command_pattern|Command Pattern]], despre care vom învăța în următoarele laboratoare.</note> |
| {{:poo-ca-cd:laboratoare:clase-abstracte-interfete:ex1.png?600|}} | {{:poo-ca-cd:laboratoare:clase-abstracte-interfete:ex1.png?600|}} | ||