This is an old revision of the document!


Laboratorul 11 – Design Patterns

Acest laborator implementează o platformă de catalog academic folosind Design Patterns. Se lucrează cu clase precum: Catalog, Course, User, Student, Parent, Teacher, Assistant, Grade. Clasa Test conține main-ul pentru testarea tuturor exercițiilor.

Problema 1 - Singleton

Implementați clasa Catalog care conține o listă cu obiecte de tip Course. Trebuie să vă asigurați că pentru această clasă va putea exista o singură instanță care să poată fi accesată din orice clasă a proiectului.

Cerințe de implementare:

  • Declarați constructorul clasei ca PRIVATE;
  • Adăugați un atribut STATIC PRIVATE de tip Catalog pentru instanța unică;
  • Implementați metoda PUBLICĂ STATICĂ getInstance();
  • Implementați metoda toString() pentru clasa Catalog.
public class Catalog {
    // TODO -- Adaugati aici implementarea exercitiului
}
 
public class Course {
}

Problema 2 - Factory

Pornind de la clasa abstractă User, definiți clasele Student, Parent, Assistant și Teacher care vor moșteni clasa User.

public abstract class User {
    protected String firstName, lastName;
 
    public User(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
 
    public String toString() {
        return firstName + " " + lastName;
    }
}

Cerințe de implementare:

  • Clasele Student, Parent, Assistant, Teacher extind User;
  • UserFactory conține metoda statică createUser() care primește tipul și returnează instanța corespunzătoare;
  • Metoda createUser(String type, String firstName, String lastName) returnează un obiect de tip User.

Exemplu de utilizare Factory:

User studentA = UserFactory.createUser("Student", "A", "Popescu");
User teacher = UserFactory.createUser("Teacher", "Teacher", "Georgescu");
User assistant = UserFactory.createUser("Assistant", "Assistant", "Popescu");
User mother = UserFactory.createUser("Parent", "M_AC", "Ionescu");

Problema 3 - Builder

Pe baza claselor definite anterior, veți completa implementarea clasei Course. Un obiect de tip Course conține:

  • un nume (String)
  • un profesor titular (Teacher)
  • o listă de asistenți (Assistant)
  • o colecție ordonată cu obiecte de tipul Grade
  • o listă de studenți

Se va folosi șablonul de proiectare Builder pentru a seta câmpurile unui obiect Course.

Clasa Grade:

public class Grade {
    private Double partialScore, examScore;
    private Student student;
    private String course;
 
    public Grade(String course, Student student) {
        partialScore = 0.0;
        examScore = 0.0;
        this.course = course;
        this.student = student;
    }
 
    public Grade(String course, Student student, Double partialScore, Double examScore) {
        this.partialScore = partialScore;
        this.examScore = examScore;
        this.course = course;
        this.student = student;
    }
 
    public void setPartialScore(Double score) {
        partialScore = score;
    }
 
    public void setExamScore(Double score) {
        examScore = score;
    }
 
    public Double getTotal() {
        return partialScore + examScore;
    }
}

Cerințe de implementare:

  • Definiți o clasă internă statică CourseBuilder în Course;
  • Builder-ul conține câmpuri identice cu cele din Course;
  • Fiecare metodă setter din Builder returnează this (pentru *method chaining*);
  • Metoda build() creează și returnează obiectul Course;
  • Modificați clasa Grade să implementeze Comparable (comparare după punctaj total);
  • Adăugați în clasa Catalog o listă cu obiecte de tip Course;
  • Definiți toString() pentru clasa Course.

Exemplu de utilizare Builder:

Course course = new Course.CourseBuilder("POO")
        .teacher((Teacher) teacher)
        .assistant((Assistant) assistant)
        .grade(new Grade("POO", (Student) studentA, 4d, 5d))
        .grade(new Grade("POO", (Student) studentB, 3d, 3d))
        .strategy(new BestExamScore())
        .build();

Problema 4 - Observer

Aplicația permite părinților unui student să se aboneze la Catalog pentru a primi notificări când copilul este notat de către un profesor sau asistent.

Interfețe:

public interface Observer {
    void update(Notification notification);
}
 
public interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(Grade grade);
}

Cerințe de implementare:

  • Catalog implementează Subject și menține lista de observatori;
  • Parent implementează Observer și ține o listă de notificări;
  • Creați clasa Notification cu atributele necesare (obligatoriu toString());
  • Modificați clasa Student să memoreze părinții (mother, father);
  • Adăugați metoda isParent(Observer parent) în Student;
  • Atenție: Primesc notificări doar părinții studentului respectiv!

Exemplu de utilizare Observer:

((Student) studentB).setMother((Parent) mother);
((Student) studentB).setFather((Parent) father);
 
catalog.addObserver((Parent) mother);
catalog.addObserver((Parent) father);
catalog.notifyObservers(new Grade("POO", (Student) studentB, 2.5d, 3d));

Problema 5 - Strategy

Fiecare profesor va aplica o politică prin care la sfârșitul semestrului selectează cel mai bun student.

Interfața Strategy:

interface Strategy {
    Student getBestStudent(Collection<Grade> grades);
}

Strategii de implementat:

  • BestPartialScore - selectează studentul cu cel mai mare punctaj pe parcurs;
  • BestExamScore - selectează studentul cu cel mai mare punctaj la examen;
  • BestTotalScore - selectează studentul cu punctajul total maxim.

Cerințe de implementare:

  • Implementați cele trei strategii;
  • Adăugați în clasa Course un atribut Strategy;
  • Adăugați metoda public Student getBestStudent() în Course;
  • Metoda returnează cel mai bun student, ținând cont de strategia setată.

Problema 6 - Visitor

Folosind șablonul Visitor, implementați funcționalitatea prin care:

  • Fiecare asistent poate completa notele de pe parcurs ale studenților;
  • Fiecare profesor poate completa notele de la examen ale studenților.

Interfețe:

public interface Element {
    void accept(Visitor visitor);
}
 
public interface Visitor {
    void visit(Assistant assistant);
    void visit(Teacher teacher);
}

Clasa auxiliară Pair:

class Pair<K, V1, V2> {
    private K key;
    private V1 value1;
    private V2 value2;
 
    public Pair(K key, V1 value1, V2 value2) {
        this.key = key;
        this.value1 = value1;
        this.value2 = value2;
    }
 
    public K getKey() { return key; }
    public V1 getValue1() { return value1; }
    public V2 getValue2() { return value2; }
}

Clasa ScoreVisitor:

public class ScoreVisitor implements Visitor {
    private HashMap<Teacher, ArrayList<Pair<Student, String, Double>>> examScores;
    private HashMap<Assistant, ArrayList<Pair<Student, String, Double>>> partialScores;
 
    public ScoreVisitor(
        HashMap<Teacher, ArrayList<Pair<Student, String, Double>>> examScores,
        HashMap<Assistant, ArrayList<Pair<Student, String, Double>>> partialScores) {
        this.examScores = examScores;
        this.partialScores = partialScores;
    }
 
    public void visit(Assistant assistant) {
        // TODO1 - completați notele de pe parcurs
    }
 
    public void visit(Teacher teacher) {
        // TODO2 - completați notele de la examen
    }
}

Cerințe de implementare:

  • Assistant și Teacher implementează Element;
  • ScoreVisitor implementează Visitor;
  • TODO1: Determinați toate notele pe care le are de trecut asistentul. Verificați dacă există un obiect Grade pentru cursul și studentul respectiv. Dacă există, setați nota de pe parcurs; dacă nu, creați un nou Grade și adăugați-l cursului;
  • TODO2: Similar pentru profesor, dar pentru nota de la examen;
  • Adăugați în Catalog metoda getCourse(String name) care returnează cursul corespunzător;
  • Adăugați în Course metoda addGrade(Grade g).

Exemplu de utilizare Visitor:

HashMap<Teacher, ArrayList<Pair<Student, String, Double>>> examScores = new HashMap<>();
ArrayList<Pair<Student, String, Double>> ar1 = new ArrayList<>();
ar1.add(new Pair(studentA, "POO", 3.6d));
examScores.put((Teacher) teacher, ar1);
 
HashMap<Assistant, ArrayList<Pair<Student, String, Double>>> partialScores = new HashMap<>();
ArrayList<Pair<Student, String, Double>> ar2 = new ArrayList<>();
ar2.add(new Pair(studentC, "POO", 4.6d));
partialScores.put((Assistant) assistant, ar2);
 
Visitor v = new ScoreVisitor(examScores, partialScores);
v.visit((Teacher) teacher);
v.visit((Assistant) assistant);

Breviar - Builder Pattern (din documentație)

Exemplu complet de Builder pentru clasa User:

public class User {
    private final String firstName;  // required
    private final String lastName;   // required
    private int age;                 // optional
    private String phone;            // optional
    private String address;          // optional
 
    private User(UserBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.phone = builder.phone;
        this.address = builder.address;
    }
 
    public static class UserBuilder {
        private final String firstName;
        private final String lastName;
        private int age;
        private String phone;
        private String address;
 
        public UserBuilder(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
 
        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }
 
        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }
 
        public UserBuilder address(String address) {
            this.address = address;
            return this;
        }
 
        public User build() {
            return new User(this);
        }
    }
 
    public static void main(String[] args) {
        User user1 = new User.UserBuilder("Lokesh", "Gupta")
                .age(30)
                .phone("1234567")
                .address("Fake address 1234")
                .build();
 
        User user2 = new User.UserBuilder("Jack", "Reacher")
                .age(40)
                .phone("5655")
                //no address
                .build();
    }
}
poo/laboratoare/11.1765725770.txt.gz · Last modified: 2025/12/14 17:22 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