Laboratorul – Design Patterns 1

În cadrul acestui laborator se va lucra pe baza scheletului pus la dispoziție.

Fiecare TODO este numerotat conform problemei ce trebuie rezolvată.

În urma realizării cerințelor, se va obține o platformă de streaming muzical.

Problema 1 - Singleton

Se cere implementarea Design Pattern-ului Singleton în cadrul clasei Spotify. Clasa Spotify reprezintă componenta principală a aplicației, gestionând datele platformei (utilizatori și melodii).

Pattern-ul Singleton asigură existența unei singure instanțe a clasei pe parcursul execuției programului.

Cerințe de implementare:

  • Declarați constructorul clasei ca PRIVATE;
  • Adăugați un atribut STATIC PRIVATE de tip Spotify pentru instanța unică;
  • Implementați o metodă PUBLICĂ STATICĂ getInstance() care:
    • creează instanța dacă nu există;
    • returnează instanța existentă;
  • Instanțiați listele (users, songs, observers) în constructorul privat.

Singleton-ul va fi punctul de acces global la datele platformei.

Problema 2 - Factory

Pornind de la clasa abstractă User, se va implementa Design Pattern-ul Factory prin intermediul claselor Regular, Premium și UltraPremium care moștenesc User.

Factory pattern centralizează logica de creare a obiectelor, ascunzând detaliile de implementare și permițând extinderea ușoară cu noi tipuri.

Valorile pentru câmpul subscription:

  • Regular: 9.99
  • Premium: 14.99
  • UltraPremium: 19.99

Cerințe de implementare:

  • Clasele Regular, Premium, UltraPremium extind User;
  • Fiecare clasă își setează subscription în constructorul propriu;
  • UserFactory conține metoda statică createUser() care primește un UserType și returnează instanța corespunzătoare;
  • În JSONReader, folosiți factory-ul pentru a crea utilizatorii.

Problema 3 - Builder

Se cere implementarea Design Pattern-ului Builder în cadrul clasei Song.

Un cântec conține: title, artists, duration, views, releaseDate, ratings.

Builder pattern permite construirea obiectelor complexe pas cu pas, oferind o alternativă la constructorii cu mulți parametri.

Cerințe de implementare:

  • Definiți o clasă internă statică Builder în Song;
  • Builder-ul conține câmpuri identice cu cele din Song;
  • Fiecare metodă setter din Builder returnează this (pentru *method chaining*);
  • Metoda build() creează și returnează obiectul Song;
  • Constructorul Song este PRIVAT și primește un Builder ca parametru;
  • În JSONReader, folosiți Builder-ul pentru a crea melodiile.

Exemplu de utilizare Builder (în JSONReader):

Song song = new Song.Builder()
        .title(title)
        .artists(artists)
        .duration(duration)
        .views(views)
        .releaseDate(releaseDate)
        .ratings(ratings)
        .build();

Exemplu de metodă setter în Builder:

public Builder title(String title) {
    this.title = title;
    return this;
}

Problema 4 - Strategy

Fiecare utilizator poate alege modul în care sunt afișate cântecele, în funcție de un criteriu de sortare preferat.

Strategy pattern permite schimbarea algoritmului de sortare la runtime, fără a modifica codul clientului.

Interfața SortingStrategy definește metoda sortedSongs(List<Song>).

Strategii de implementat:

  • AverageScoreStrategy - sortare DESCRESCĂTOARE după scorul mediu;
  • TotalViewsStrategy - sortare DESCRESCĂTOARE după numărul de views;
  • ReleaseYearStrategy - sortare CRESCĂTOARE după data lansării (*oldest first*).

Cerințe de implementare:

  • Implementați cele trei strategii;
  • User.getSortedSongs() delegă sortarea către strategia setată;
  • În JSONReader, citiți câmpul “sortingStrategy” din JSON și setați strategia corespunzătoare (valori: “averageScore”, “totalViews”, “releaseYear”).

Hint pentru sortare cu Comparator:

// Sortare DESCRESCĂTOARE după un câmp
songs.sort((s1, s2) -> s2.getField().compareTo(s1.getField()));
 
// Sortare CRESCĂTOARE după un câmp
songs.sort((s1, s2) -> s1.getField().compareTo(s2.getField()));

Problema 5 - Observer

Utilizatorii platformei pot primi notificări când un cântec nou este adăugat.

Observer pattern permite notificarea automată a obiectelor interesate (observers) când starea unui obiect (subject) se schimbă.

Interfețele din schelet:

  • Subject - definește addObserver, removeObserver, notifyObservers
  • Observer - definește update(String message)

Cerințe de implementare:

  • Spotify implementează Subject și menține lista de observatori;
  • User implementează Observer și afișează mesajul primit în update();
  • În addSong(), după adăugarea melodiei, notificați observatorii cu mesajul: “New song added: <titlu>”;
  • În readData(), după încărcarea utilizatorilor, adăugați-i ca observatori.

Problema 6 - Visitor

Pentru calculul venitului total lunar, se va folosi Design Pattern-ul Visitor.

Visitor pattern permite adăugarea de operații noi asupra obiectelor fără a modifica clasele acestora. „Vizitorul” parcurge elementele și aplică operații specifice fiecărui tip.

Interfețele din schelet:

  • Element - definește accept(Visitor)
  • Visitor - definește visit() pentru fiecare tip de utilizator

Formula de calcul a venitului per utilizator:

  • revenue = subscription * (1 - discount/100.0) * VAT
  • unde VAT = 1.19

Cerințe de implementare:

  • User implementează Element;
  • Regular, Premium, UltraPremium implementează accept() apelând visitor.visit(this);
  • RevenueVisitor implementează Visitor cu metode visit() pentru fiecare tip;
  • RevenueVisitor acumulează totalRevenue și oferă getTotalRevenue();
  • Spotify.calculateRevenue() creează un visitor, parcurge userii și returnează venitul total.

Exemplu de utilizare Visitor (în Spotify.calculateRevenue):

RevenueVisitor visitor = new RevenueVisitor();
for (User user : users) {
    user.accept(visitor);
}
return visitor.getTotalRevenue();

BONUS

Implementați pattern-ul Observer și pentru rating-uri.

Când un utilizator adaugă un rating unui cântec, toți utilizatorii care au dat anterior un rating aceluiași cântec vor fi notificați.

Cerințe de implementare:

  • Song menține o listă de observatori (utilizatorii care au dat rating);
  • La addRating(), adăugați rating-ul, apoi notificați observatorii existenți cu mesajul: “New rating for: <titlu>”;
  • Utilizatorul care adaugă rating-ul devine și el observator pentru viitor.
poo/laboratoare/11-backup.txt · Last modified: 2025/12/14 17:19 by george.tudor1906
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