This shows you the differences between two versions of the page.
poo:laboratoare:13 [2021/01/17 18:59] carmen.odubasteanu |
poo:laboratoare:13 [2023/12/09 11:42] (current) carmen.odubasteanu |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Laboratorul 13. ===== | + | ===== Laboratorul 11. ===== |
=== Problema 1 - Singleton === | === Problema 1 - Singleton === | ||
Line 5: | Line 5: | ||
Implementați o clasa **Catalog** care conține o lista cu obiecte de tip **Course**. | Implementați o clasa **Catalog** care conține o lista cu obiecte de tip **Course**. | ||
Va trebui sa va asigurați ca pentru aceasta clasa va putea exista o singura instanța care sa poata fi accesata din orice clasa a proiectului. Implementati metoda **toString** pentru clasa **Catalog**. | Va trebui sa va asigurați ca pentru aceasta clasa va putea exista o singura instanța care sa poata fi accesata din orice clasa a proiectului. Implementati metoda **toString** pentru clasa **Catalog**. | ||
- | ''public class Catalog { | + | |
+ | <code java> | ||
+ | public class Catalog { | ||
// TODO -- Adaugati aici implementarea exercitiului | // TODO -- Adaugati aici implementarea exercitiului | ||
} | } | ||
public class Course { | public class Course { | ||
} | } | ||
- | '' | + | </code> |
- | === Problema 2 === | + | |
- | Realizați o arhitectură unificată, similară cu Collections, pentru manipularea listelor care să conțină: | + | |
- | * interfața //**Function**//, parametrizată corespunzător, care conține o metodă //**execute**//, având ca parametru un obiect de tip //**A**// și un rezultat de tip //**B**//, unde //**A**// și //**B**// sunt două tipuri formale; | + | |
- | * interfața //**Addition**// folosită pentru a calcula suma a două numere de tip //**T**//, unde //**T**// este un subtip al lui //**Number**// (aceasta va conține o metodă //**zero**// care va întoarce elementul neutru al operației de adunare și o metodă //**add**//, care primește două obiecte de tip //**T**// și returnează suma lor); | + | |
- | * doi algoritmi polimorfici: //**reverse**// care inversează elementele unei liste și //**sum**// care calculează suma elementelor din listă; acești algoritmi trebuie să poată fi folosiți pe implementări diferite de liste, deoarece le abordează la nivel de interfață; | + | |
- | * o serie de metode care au un comportament similar cu funcționalele din paradigma funcțională. În cadrul acestei paradigme, funcțiile sunt valori de ordinul 1 ce pot fi manipulate ca orice altă valoare, iar funcționalele sunt funcții care manipulează alte funcții, primindu-le ca argumente sau returnându-le ca rezultat, în functie de cum e nevoie, fiind foarte utile în aplicarea anumitor modele de calcul des folosite. | + | |
- | Veți porni implementarea de la clasa **//ListUtil//**, pusă la dispoziție în arhiva laboratorului. | + | === Problema 2 - Factory === |
+ | Pornind de la clasa abstracta **User**, definiți clasele **Student**, **Parent**, **Assistant** și **Teacher** care vor moșteni clasa **User**: | ||
- | Explicatii pentru functionale: | + | <code java> |
+ | 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; | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
- | -**foldl**(function, init, list)- returnează rezultatul aplicării functiei function pe rând asupra unui element din listă si a unui acumulator init. Ordinea folosirii elementelor din listă este de la stânga la dreapta; | + | Pentru a putea realiza o instanțiere ușoara a obiectelor pentru aceste tipuri de clase, veți implementa o clasa **UserFactory** care va avea o metoda __statica__ **createUser** ce va returna un obiect de tip **User** (se va folosi șablonul de proiectare **Factory**). |
- | Exemplu: | + | |
- | foldl(f(x, y) = x + y, 5, [0, 1, 2, 3]) => 11 | + | |
- | -**foldr**(function, init, list)- are un comportament similar cu foldl, însă ordinea folosirii elementelor din listă este de la dreapta la stânga; | + | Pentru testare folositi clasa **Test** de mai jos, in care veti comenta cerintele neimplementate inca: |
- | Exemplu: | + | |
- | foldr(f(x, y) = y, 4, [0, 1, 2, 3]) => 0 | + | |
- | -**map**(function, list)- returnează lista rezultatelor aplicării unei functii f asupra fiecărui element dintr-o listă; | + | <code java> |
- | Exemplu: | + | class Test { |
- | map(f(x) = 2*x,[0, 1, 2, 3]) => [0, 2, 4, 6] | + | 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"); | ||
- | -**filter**(predicat, list)- returnează lista elementelor dintr-o listă care satisfac un predicat p (un predicat îl vom percepe ca o functie care are un rezultat de tip Boolean); | + | User mother = UserFactory.createUser("Parent", "M_AC", "Ionescu"); |
- | Exemplu: | + | User father = UserFactory.createUser("Parent", "T_AC", "Ionescu"); |
- | filter(f(x) = x % 2 == 0, P[0, 1, 2, 3]) => [0, 2] | + | |
+ | 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); | ||
- | -**reduce**(function, list)- aplică functia pentru primele două elemente din lista, apoi pentru rezultatul obtinut anterior si urmatorul element si tot asa; | + | catalog.addObserver((Parent) mother); |
- | Exemplu: | + | catalog.addObserver((Parent) father); |
- | reduce(f(x, y) = x + y, [47, 11, 42, 13]) => 113 | + | 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> | ||
- | -**all**(predicat, list)- primeste un predicat (metoda ce are ca rezultat un boolean) si verifică dacă toate elementele din listă satisfac predicatul; | + | === Problema 3 - Builder === |
- | Exemplu: | + | |
- | all(f(x) = x > 0, [0, 1, 2, 3]) => True ; | + | |
- | all(f(x) = x % 2 == 0, [0, 1, 2, 3]) => False | + | |
- | -**any**(predicat, list)- primeste un predicat si verifică dacă exista cel putin un element în lista care satisface predicatul. | + | Pe baza claselor definite anterior, veți completa implementarea clasei **Course**. În cadrul aplicației noastre, un obiect de tipul **Course** o sa conțina: un nume (de tipul **String**), un profesor titular, o lista de asistenți, o colecție ordonata cu obiecte de tipul **Grade** și o lista de studenți. |
- | Exemplu: | + | |
- | any(f(x) = x < 0,[1, 2, 3, 4]) => False ; | + | |
- | any(f(x) = x % 2 == 0,[1, 2, 3]) => True | + | |
- | Pentru testare, completati exemplele din clasa Test. | + | Pentru a putea seta câmpurile unui obiect de tip **Course**, veți folosi șablonul de proiectare **Builder**. |
+ | ! Definiti **toString** pentru clasa **Course**. | ||
- | === Problema 3 === | + | <code java> |
- | Sa se scrie un program pentru afisarea pe ecran a liniilor aflate pe pozitii impare dintr-un fisier text. Fiecare linie va fi precedata de numarul ei si un spatiu. In implementare, se va folosi un obiect de tip //**LineNumberReader**//. Tratati toate exceptiile care ar putea sa apara exact acolo unde apar! Atentie la inchiderea fisierelor – sa se faca chiar daca apare exceptie la citire! | + | public class Grade { |
+ | private Double partialScore, examScore; | ||
+ | private Student student; | ||
+ | private String course; | ||
- | Pentru validarea acestei cerinte, puteti folosi fisierul text //test01.in// pus la dispozitie in arhiva laboratorului. | + | public Grade(String course, Student student) { |
+ | partialScore = 0.0; | ||
+ | examScore = 0.0; | ||
+ | this.course = course; | ||
+ | this.student = student; | ||
+ | } | ||
- | === Problema 4 === | + | public Grade(String course, Student student,Double partialScore, Double examScore ) { |
- | Sa se scrie un program care citeste un text de la tastura si il salveaza intr-un fisier pe disc. Citirea se va face pana la introducerea cuvantului //**exit**//. In implementare se va uzita metoda //**readLine()**// pentru un obiect de tip //**DataInputStream**// sau //**BufferedReader**//. Tratati toate exceptiile care ar putea sa apara! | + | 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 doua obiecte de tip **Grade** vor putea sa fie comparate (în funcție de punctajul total). | ||
+ | De asemenea, va trebui sa adaugați în clasa **Catalog** o lista cu obiecte de tip **Course**. | ||
+ | |||
+ | <note> Folositi pentru testare main-ul de la Factory! </note> | ||
+ | |||
+ | === Problema 4 - Observer === | ||
+ | Aplicația noastra le permite parinților unui student sa se aboneze la **Catalog** pentru a putea primi notificari în momentul în care copilul este notat de catre un profesor sau de catre un asistent. | ||
+ | Pentru a putea realiza acest lucru, veți folosi șablonul de proiectare **Observer** și veți implementa o clasa **Notification ** (stabiliți voi care sunt atributele și metodele din aceasta clasa – este obligatoriu sa fie suprascrisa metoda **toString**). | ||
+ | |||
+ | Ce clasa va implementa interfața **Observer** și ce clasa va implementa interfața **Subject**? | ||
- | === Problema 5 === | ||
- | Sa se implementeze un program care citeste din fisierul //test02.in// un text si determina numarul de cuvinte din text. Pentru citire se vor utiliza un obiect de tip //**FileReader**// si unul de tip //**StreamTokenizer**//. | ||
<code java> | <code java> | ||
- | FileReader in = new FileReader(new File("test02.in")); | + | public interface Observer { |
- | StreamTokenizer str = new StreamTokenizer(in); | + | void update(Notification notification); |
+ | } | ||
+ | |||
+ | public interface Subject { | ||
+ | void addObserver(Observer observer); | ||
+ | void removeObserver(Observer observer); | ||
+ | void notifyObservers(Grade grade); | ||
+ | } | ||
</code> | </code> | ||
- | {{:poo:laboratoare:arhiva_13.zip|Arhiva laborator}} | + | <note> |
+ | Hint! | ||
+ | |||
+ | 1.Parent va tine minte si o lista a notificarilor, iar Catalog o lista a Observatorilor. | ||
+ | |||
+ | 2. Atentie! Primesc notificari doar parintii studentului respectiv! Modificati clasa Student astfel incat sa avem memorati si parintii pentru fiecare Student si adaugati o metoda isParent(Observer parent) care verifica daca un observator este parintele studentului current. | ||
+ | </note> | ||
+ | <note> Folositi pentru testare main-ul de la Factory! </note> | ||
+ | |||
+ | === Problema 5 - Strategy === | ||
+ | |||
+ | Fiecare profesor va aplica o politica prin care la sfârșitul semestrului selecteaza cel mai bun student. Pentru a realiza acest lucru în cadrul implementarii, va trebui sa folosiți șablonul de proiectare **Strategy**. Veți defini câte o clasa pentru fiecare din urmatoarele strategii: | ||
+ | |||
+ | - 1. **BestPartialScore** – aceasta strategie va selecta studentul care are cel mai mare punctaj în timpul semestrului; | ||
+ | - 2. **BestExamScore** – aceasta strategie va selecta studentul care are cel mai mare punctaj în examen; | ||
+ | - 3. **BestTotalScore** – aceasta strategie va selecta studentul care are punctajul total maxim. | ||
+ | |||
+ | <code java> | ||
+ | interface Strategy { | ||
+ | Student getBestStudent(Collection<Grade> grades); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Veți adauga în clasa **Course** un atribut **Strategy**, si o metoda cu antetul: | ||
+ | public Student **getBestStudent**(); | ||
+ | Metoda va returna cel mai bun student, tinand cont de strategia setata de profesor pentru curs. | ||
+ | |||
+ | <note> Folositi pentru testare main-ul de la **Factory**! </note> | ||
+ | |||
+ | === Problema 6 - Visitor === | ||
+ | |||
+ | Folosind șablonul de proiectare **Visitor**, vom implementa funcționalitatea prin care fiecare asistent o sa poata completa notele de pe parcurs ale studenților, iar fiecare profesor o sa poata completa notele de la examen ale studenților sai. | ||
+ | Pentru acest lucru, vom porni de la urmatoarele 2 interfețe: **Element** și **Visitor**. | ||
+ | <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 doua dicționare în care sunt stocate notele studentilor pentru examene și pentru parcurs. | ||
+ | - Dicționarul **examScores** va avea cheia de tip **Teacher** și valoare de tip lista 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 similara, dar pentru notele de pe parcurs atribuite de asistenți. | ||
+ | |||
+ | În continuare, se va prezenta implementarea de la care veți porni pentru aceasta clasa: | ||
+ | |||
+ | <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 respectiva. Veți verifica daca pentru o intrare din lista de note exista sau nu un obiect de tip **Grade** pentru cursul indicat corespunzator studentului. | ||
+ | Daca exista, atunci se va seta nota de pe parcurs pentru acel obiect, daca nu exista, se va crea un nou obiect **Grade** și se va adauga cursului. | ||
+ | |||
+ | • **TODO2** – veți determina toate notele pe care le are de trecut profesorul primit ca parametru de metoda respectiva. Veți verifica daca pentru o intrare din lista de note exista sau nu un obiect de tip **Grade** pentru cursul indicat corespunzator studentului. | ||
+ | Daca exista, atunci se va seta nota de la examen pentru acel obiect, daca nu exista, se va crea un nou obiect **Grade** și se va adauga cursului. | ||
+ | |||
+ | <note>**Hint!** | ||
+ | Veti adauga metodele de care aveti nevoie in clasele utilizate. | ||
+ | |||
+ | Exemple: | ||
+ | In **Catalog** veti adauga o metoda public **Course** **getCourse**(**String** name), care intoarce obiectul Course corespunzator numelui trimis ca parametru. | ||
+ | |||
+ | In **Course** o metoda **addGrade**(**Grade** g); | ||
+ | Etc. | ||
+ | </note> | ||
+ | |||
+ | <note> Folositi pentru testare main-ul de la **Factory**! </note> | ||
+ | <hidden>{{:poo:laboratoare:arhiva_13.zip|Arhiva laborator}} | ||
+ | </hidden> | ||