This shows you the differences between two versions of the page.
|
poo:laboratoare:11 [2017/12/06 08:26] mihai.nan |
poo:laboratoare:11 [2025/12/14 17:54] (current) george.tudor1906 |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ===== Laboratorul 11. ===== | ||
| - | === Problema 1 === | + | ===== Laboratorul 11 – Design Patterns (1) ===== |
| - | Pornind de la clasa **//Book//**, pusă la dispoziție în arhiva laboratorului, realizați o listă, obiect de tip **//JList//**, care să afișeze o serie de cărți. | + | |
| - | În implementare, constructorul obiectului **//JList//** primește ca parametru un obiect de tip **//Vector//**, care o să conțină elemente de tip **//Book//**. | + | <hidden> |
| + | {{:poo:laboratoare:rezolvare_dp_catalog.zip|}} | ||
| + | </hidden> | ||
| - | <note important>Lista va afisa pentru fiecare carte titlul, autorul si numele icon-ului corespunzator (nu imaginea)! | + | === Problema 1 - Singleton === |
| - | Lista trebuie sa fie una scrolabila.</note> | + | |
| + | Implementați o clasă **Catalog** care conține o listă cu obiecte de tip **Course**. | ||
| + | Va trebui să vă asigurați că pentru această clasă va putea exista o singură instanță | ||
| + | care să poată fi accesată din orice clasă a proiectului. Implementați metoda toString | ||
| + | pentru clasa Catalog. | ||
| - | ===Problema 2=== | + | <code java> |
| + | public class Catalog { | ||
| + | // TODO -- Adaugati aici implementarea exercitiului | ||
| + | } | ||
| + | |||
| + | public class Course { | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | === Problema 2 - Factory === | ||
| - | Modificați aplicația realizată la problema anterioară, folosind de această dată, în loc de un obiect de tip **//Vector//**, un obiect de tip **//DefaultListModel//**. De asemenea, adaugați două câmpuri text și doua etichete pentru titlul cărții și autor. Cele patru elemente se vor plasa într-un panou separat. Adaugați listei un ascultător de tip **//ListSelectionListener//**. Atunci când utilizatorul va selecta un câmp al listei, trebuie să se introducă informațiile aferente cărții selectate în cele două câmpuri text. | + | Pornind de la clasa abstractă **User**, definiți clasele **Student**, **Parent**, |
| + | **Assistant** și **Teacher** care vor moșteni clasa **User**: | ||
| - | Pentru a evita producerea unei exceptii, uzitati codul de mai jos. | ||
| <code java> | <code java> | ||
| - | @Override | + | public abstract class User { |
| - | public void valueChanged(ListSelectionEvent e) { | + | protected String firstName, lastName; |
| - | //JList listBook - membrul al clasei | + | |
| - | if(listBook.isSelectionEmpty()) | + | public User(String firstName, String lastName) { |
| - | return; | + | this.firstName = firstName; |
| + | this.lastName = lastName; | ||
| + | } | ||
| + | |||
| + | public String toString() { | ||
| + | return firstName + " " + lastName; | ||
| + | } | ||
| } | } | ||
| </code> | </code> | ||
| - | <note tip>GridLayout</note> | + | Pentru a putea realiza o instanțiere ușoară a obiectelor pentru aceste tipuri de clase, |
| + | veți implementa o clasă **UserFactory** care va avea o metodă statică **createUser** ce | ||
| + | va returna un obiect de tip User (se va folosi șablonul de proiectare Factory). | ||
| + | === Problema 3 - Builder === | ||
| - | ===Problema 3=== | + | Pe baza claselor definite anterior, veți completa implementarea clasei **Course**. |
| - | Pentru aplicația anterioară, implementați o modalitate de ștergere a unei celule selectate; operația se va executa la apăsarea unui buton adăugat pentru aceasta. | + | În cadrul aplicației noastre, un obiect de tipul Course o să conțină: |
| + | * un nume (de tipul String) | ||
| + | * un profesor titular | ||
| + | * o listă de asistenți | ||
| + | * o colecție ordonată cu obiecte de tipul Grade | ||
| + | * o listă de studenți | ||
| - | ===Problema 4=== | + | Pentru a putea seta câmpurile unui obiect de tip Course, veți folosi șablonul de |
| - | Realizați o aplicație care să permită afișarea tuturor fișierelor dintr-un director. Aceasta va conține, în partea stângă, un obiect de tip **//JTree//** ce va afișa directoarele și fișierele aflate în directorul părinte pe care dorim să îl explorăm, iar în partea dreapta un tabel, obiect de tip **//JTable//**, care va conține informații detaliate pentru fiecare fișier din directorul părinte. Mai exact, tabelul va avea următoarele câmpuri: numele, dimensiunea, data ultimei modificări și tipul. | + | proiectare **Builder**. Definiți toString pentru clasa Course. |
| - | {{:poo:laboratoare:aplicatie2.png|}} | + | |
| + | <code java> | ||
| + | public class Grade { | ||
| + | private Double partialScore, examScore; | ||
| + | private Student student; | ||
| + | private String course; | ||
| - | ===Problema 5=== | + | public Grade(String course, Student student) { |
| + | partialScore = 0.0; | ||
| + | examScore = 0.0; | ||
| + | this.course = course; | ||
| + | this.student = student; | ||
| + | } | ||
| - | Pornind de la aplicația implementată la problema precedentă, sș se definească două clase ascultător compatibile cu interfața **//ListSelectionListener//**, implementând metoda **//valueChanged()//**, cu argument de tip **//ListSelectionEvent//**. Metoda extrage numărul liniei sau coloanei, uzitând metoda **//getMinSelectionIndex()//**, și afișează acest număr într-un câmp text. Să se adauge cei doi | + | public Grade(String course, Student student, Double partialScore, Double examScore) { |
| - | ascultători la obiectele **//ListSelectionModel//** extrase cu metoda **//getSelectionModel()//**. | + | 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; | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Modificați clasa **Grade** astfel încât două obiecte de tip Grade vor putea să fie | ||
| + | comparate (în funcție de punctajul total). De asemenea, va trebui să adăugați în | ||
| + | clasa Catalog o listă cu obiecte de tip Course. | ||
| + | |||
| + | === Problema 4 - Observer === | ||
| + | |||
| + | Aplicația noastră le permite părinților unui student să se aboneze la Catalog pentru | ||
| + | a putea primi notificări în momentul în care copilul este notat de către un profesor | ||
| + | sau de către un asistent. Pentru a putea realiza acest lucru, veți folosi șablonul | ||
| + | de proiectare **Observer** și veți implementa o clasă **Notification** (stabiliți voi | ||
| + | care sunt atributele și metodele din această clasă – este obligatoriu să fie | ||
| + | suprascrisă metoda toString). | ||
| + | |||
| + | Ce clasă va implementa interfața Observer și ce clasă va implementa interfața Subject? | ||
| <code java> | <code java> | ||
| - | ListSelectionModel rowSM = table.getSelectionModel(); | + | public interface Observer { |
| - | ListSelectionModel colSM = table.getColumnModel().getSelectionModel(); | + | void update(Notification notification); |
| + | } | ||
| + | |||
| + | public interface Subject { | ||
| + | void addObserver(Observer observer); | ||
| + | void removeObserver(Observer observer); | ||
| + | void notifyObservers(Grade grade); | ||
| + | } | ||
| </code> | </code> | ||
| + | Hint: | ||
| + | * Parent va ține minte și o listă a notificărilor, iar Catalog o listă a Observatorilor. | ||
| + | * Atenție! Primesc notificări doar părinții studentului respectiv! Modificați clasa Student astfel încât să avem memorați și părinții pentru fiecare Student și adăugați o metodă isParent(Observer parent) care verifică dacă un observator este părintele studentului curent. | ||
| - | ===Problema 6=== | + | === Problema 5 - Strategy === |
| - | Să se adauge aplicației de la problema 2 o clasă **//BookRenderer//**, care să extindă **//JPanel//** și să implementeze **//ListCellRenderer//**. Această clasă va conține trei obiecte de tip **//JLabel//** (Titlul, Autorul si Imaginea), pentru a schimba aspectul listei inițiale. De această dată, pentru fiecare carte vom afișa titlul, autorul, dar și imaginea aferentă. Atunci când o celulă este selectată o să apară un fundal de o anumită culoare, iar când nu este selectată verde dacă este pe o poziție pară și galben dacă este pe una impară. | + | Fiecare profesor va aplica o politică prin care la sfârșitul semestrului selectează |
| + | cel mai bun student. Pentru a realiza acest lucru în cadrul implementării, va trebui | ||
| + | să folosiți șablonul de proiectare **Strategy**. Veți defini câte o clasă pentru | ||
| + | fiecare din următoarele strategii: | ||
| + | |||
| + | * **BestPartialScore** – această strategie va selecta studentul care are cel mai mare punctaj în timpul semestrului; | ||
| + | * **BestExamScore** – această strategie va selecta studentul care are cel mai mare punctaj în examen; | ||
| + | * **BestTotalScore** – această strategie va selecta studentul care are punctajul total maxim. | ||
| <code java> | <code java> | ||
| - | icon.setIcon(new ImageIcon("Imagini/" + book.getIconName() + ".jpg")); | + | interface Strategy { |
| + | Student getBestStudent(Collection<Grade> grades); | ||
| + | } | ||
| </code> | </code> | ||
| - | {{:poo:laboratoare:aplicatie.png|}} | + | Veți adăuga în clasa **Course** un atribut Strategy, și o metodă cu antetul: |
| + | //public Student getBestStudent();// | ||
| + | Metoda va returna cel mai bun student, ținând cont de strategia setată de profesor | ||
| + | pentru curs. | ||
| + | |||
| + | === Problema 6 - Visitor === | ||
| + | |||
| + | Folosind șablonul de proiectare **Visitor**, vom implementa funcționalitatea prin care | ||
| + | fiecare asistent o să poată completa notele de pe parcurs ale studenților, iar fiecare | ||
| + | profesor o să poată completa notele de la examen ale studenților săi. | ||
| + | |||
| + | <code java> | ||
| + | public interface Element { | ||
| + | void accept(Visitor visitor); | ||
| + | } | ||
| + | |||
| + | public interface Visitor { | ||
| + | void visit(Assistant assistant); | ||
| + | void visit(Teacher teacher); | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Clasele **Assistant** și **Teacher** vor implementa interfața Element, iar clasa | ||
| + | **ScoreVisitor** va implementa interfața Visitor. În clasa ScoreVisitor vom avea | ||
| + | două dicționare în care sunt stocate notele studenților pentru examene și pentru parcurs. | ||
| + | * Dicționarul **examScores** va avea cheia de tip Teacher și valoare de tip listă de Pair (Student, Numele cursului – ca String, nota pe care a acordat-o studentului pentru cursul indicat – ca Double). | ||
| + | * Dicționarul **partialScores** cu semnificație similară, dar pentru notele de pe parcurs atribuite de asistenți. | ||
| + | |||
| + | <code java> | ||
| + | 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; } | ||
| + | } | ||
| + | |||
| + | 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 | ||
| + | } | ||
| + | |||
| + | public void visit(Teacher teacher) { | ||
| + | // TODO2 | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | * **TODO1** – veți determina toate notele pe care le are de trecut asistentul primit ca parametru de metoda respectivă. Veți verifica dacă pentru o intrare din lista de note există sau nu un obiect de tip Grade pentru cursul indicat corespunzător studentului. Dacă există, atunci se va seta nota de pe parcurs pentru acel obiect, dacă nu există, se va crea un nou obiect Grade și se va adăuga cursului. | ||
| + | * **TODO2** – veți determina toate notele pe care le are de trecut profesorul primit ca parametru de metoda respectivă. Veți verifica dacă pentru o intrare din lista de note există sau nu un obiect de tip Grade pentru cursul indicat corespunzător studentului. Dacă există, atunci se va seta nota de la examen pentru acel obiect, dacă nu există, se va crea un nou obiect Grade și se va adăuga cursului. | ||
| + | |||
| + | Hint! Veți adăuga metodele de care aveți nevoie în clasele utilizate. | ||
| + | Exemple: În Catalog veți adăuga o metodă //public Course getCourse(String name)//, care | ||
| + | întoarce obiectul Course corespunzător numelui trimis ca parametru. | ||
| + | În Course o metodă //addGrade(Grade g);//. Etc. | ||
| + | |||
| + | === Clasa Test (pentru testare) === | ||
| + | |||
| + | <code java> | ||
| + | class Test { | ||
| + | public static void main(String[] args) { | ||
| + | //testare exercitiu 2 | ||
| + | User studentA = UserFactory.createUser("Student", "A", "Popescu"); | ||
| + | User studentB = UserFactory.createUser("Student", "B", "Ionescu"); | ||
| + | User studentC = UserFactory.createUser("Student", "C", "Ionescu"); | ||
| + | User mother = UserFactory.createUser("Parent", "M_AC", "Ionescu"); | ||
| + | User father = UserFactory.createUser("Parent", "T_AC", "Ionescu"); | ||
| + | User teacher = UserFactory.createUser("Teacher", "Teacher", "Georgescu"); | ||
| + | User assistant = UserFactory.createUser("Assistant", "Assistant", "Popescu"); | ||
| + | |||
| + | //testare exercitiu 3+5 | ||
| + | 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(); | ||
| + | System.out.println("Curs: "+ course); | ||
| + | System.out.println("Best Student:" + course.getBestStudent()); | ||
| + | |||
| + | //testare exercitiu 1+3+5 | ||
| + | Catalog catalog = Catalog.getInstance(); | ||
| + | catalog.addCourse(course); | ||
| + | |||
| + | //testare exercitiu 4 | ||
| + | ((Student) studentB).setMother((Parent) mother); | ||
| + | ((Student) studentB).setFather((Parent) father); | ||
| + | ((Student) studentC).setMother((Parent) mother); | ||
| + | catalog.addObserver((Parent) mother); | ||
| + | catalog.addObserver((Parent) father); | ||
| + | catalog.notifyObservers(new Grade("POO", (Student)studentB,2.5d,3d)); | ||
| + | |||
| + | //testare exercitiu 6 | ||
| + | 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); | ||
| + | System.out.println("Actualizare teacher:" + catalog); | ||
| + | v.visit((Assistant)assistant); | ||
| + | System.out.println("Actualizare assistant:" + catalog); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| - | {{:poo:laboratoare:laborator11.zip|Arhiva laborator}} | ||