This shows you the differences between two versions of the page.
|
poo:breviare:breviar-11 [2025/11/30 16:29] george.tudor1906 [Breviar 11] |
poo:breviare:breviar-11 [2025/12/14 17:41] (current) george.tudor1906 |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Breviar 11 ====== | ||
| - | ====== Breviar 9 ====== | + | === Introducere în Design Patterns === |
| - | === Interfețe grafice (GUI) === | + | == 1. Ce reprezintă design patterns? == |
| - | === 1. Introducere === | + | Design patterns reprezintă soluții generale, reutilizabile, pentru probleme des întâlnite în cadrul software design. |
| + | Un design pattern este o schemă a unei soluții pentru o problemă de design (nu reprezintă un algoritm sau o bucată de cod care poate fi aplicată direct), | ||
| + | ce poate ușura munca programatorului și poate duce la simplificarea și eficientizarea arhitecturii unei aplicații. | ||
| - | == 1.1 Contextul interfețelor grafice == | + | == 2. Tipuri de design patterns == |
| - | În cazul programelor pe care le-am făcut până acum, toate mesajele și răspunsurile apăreau ca linii de text sugestive, ecranul fiind folosit în mod text. | + | Există 3 tipuri de design patterns, în funcție de aspectul și de funcționalitatea obiectelor: |
| - | Un astfel de stil de comunicare nu este atractiv pentru utilizatori, motiv pentru care se preferă dialogul prin **interfețe grafice** sau **GUI** (//Graphical User Interface//), ecranul fiind folosit în mod grafic. | + | * **Behavioral Patterns**: tratează modul de interacționare între obiecte (Observer, Strategy, Visitor, Command); |
| + | * **Creational Patterns**: tratează modul de creare a obiectelor (Factory, Singleton, Builder); | ||
| + | * **Structural Patterns**: tratează modul cum este reprezentat un obiect și cum sunt relațiile între entități (Decorator, Composite, Proxy, Facade, Adapter). | ||
| - | <note important> | + | === 1. Creational Patterns === |
| - | În trecerea de la o versiune la alta, bibliotecile de clase care oferă servicii grafice au suferit, probabil, cele mai mari schimbări. Acest lucru se datorează, pe de o parte, dificultății legate de implementarea noțiunii de portabilitate, iar pe de altă parte nevoii de a integra mecanismele GUI cu tehnologii apărute și dezvoltate ulterior. | + | |
| - | </note> | + | |
| - | == 1.2 Modalități de creare a interfețelor grafice == | + | == 1.1 Singleton Pattern == |
| - | În momentul actual, există două modalități de a crea o aplicație cu interfață grafică: | + | === Descriere === |
| - | * **AWT (Abstract Windowing Toolkit)** - este API-ul inițial pus la dispoziție începând cu primele versiuni de Java; | + | Uneori ne dorim să avem un obiect care să apară doar o singură dată într-o aplicație (de exemplu conducătorul unei țări). |
| - | * **Swing** - este parte dintr-un proiect mai amplu numit **JFC (Java Foundation Classes)** creat în urma colaborării dintre Sun, Netscape și IBM, care se bazează pe modelul AWT, extinzând funcționalitatea acestuia și adăugând sau înlocuind unele componente pentru dezvoltarea aplicațiilor GUI. | + | De aceea folosim **Singleton**, un mod prin care restricționăm numărul de instanțieri ale unei clase: clasa are o singură instanță, |
| + | care va fi folosită în întreg proiectul. | ||
| - | <note tip> | + | Pentru a asigura restricționarea: |
| - | Este preferabil ca aplicațiile Java să fie create folosind tehnologia **Swing**, deoarece aceasta pune la dispoziție o paletă mult mai largă de facilități, însă nu se va renunța complet la AWT, deoarece aici există clase esențiale, reutilizate în Swing. | + | |
| - | </note> | + | |
| - | === 2. Pachetul Swing === | + | * constructorul clasei de tip Singleton este **privat** (astfel blocăm instanțierea multiplă din exterior); |
| + | * avem un membru **static** și **privat** care reține instanța unică; | ||
| + | * avem o metodă **statică** și **publică** prin care returnăm instanța (se creează dacă nu există deja). | ||
| - | == 2.1 Caracteristici == | + | Există două abordări frecvente: |
| + | * **lazy instantiation** (instanța se creează la prima cerere); | ||
| + | * **eager instantiation** (instanța se creează imediat, la încărcarea clasei). | ||
| - | Componentele **Swing**, spre deosebire de predecesoarele din versiunile Java anterioare, sunt implementate în întregime în Java. Aceasta are ca rezultat o mai bună compatibilitate cu platforme diferite decât în cazul folosirii componentelor AWT. | + | <code java> |
| + | public class SingletonClass { | ||
| + | /* | ||
| + | la inceput, inainte de prima si singura instantiere a clasei SingletonClass | ||
| + | va avea valoarea null | ||
| + | */ | ||
| + | private static SingletonClass obj = null; | ||
| - | Unul din principalele deziderate ale tehnologiei Swing a fost să pună la dispoziție un set de componente GUI extensibile care să permită dezvoltarea rapidă de aplicații Java cu interfață grafică competitivă, din punct de vedere comercial. | + | public int value = 10; |
| - | Cel mai important pachet, care conține componentele de bază este **javax.swing**. | + | // lasam constructorul clasei privat pentru a nu fi accesat din exterior |
| + | private SingletonClass() { | ||
| + | // do stuff | ||
| + | System.out.println("Instantiam!"); | ||
| + | } | ||
| - | == 2.2 Elementele unei interfețe utilizator == | + | // metoda prin care se creaza unica instanta a clasei |
| + | // lazy instantiation | ||
| + | public static SingletonClass getInstance() { | ||
| + | // daca clasa nu a fost instantiata inainte, o facem acum | ||
| + | if (obj == null) | ||
| + | obj = new SingletonClass(); | ||
| + | return obj; | ||
| + | } | ||
| - | Orice interfață utilizator Java este compusă din următoarele elemente: | + | public void show() { |
| + | System.out.println("Singleton is magic"); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| - | * **Componente** - orice poate fi plasat pe o interfață utilizator, cum ar fi butoane, liste de derulare, meniuri pop-up, casete de validare sau câmpuri de text; | + | === Avantaje / Dezavantaje === |
| - | * **Containere** - acestea reprezintă componente care pot conține alte componente (de exemplu panouri, casete de dialog sau ferestre independente); | + | |
| - | * **Administratori de dispunere** - reprezintă obiecte care definesc modul în care sunt aranjate (dispuse) componentele într-un container. Administratorul de dispunere nu este vizibil într-o interfață, însă sunt vizibile rezultatele "muncii" sale. | + | |
| - | <note tip> | + | Un avantaj este accesul ușor la instanța globală, fără a avea nevoie să o transmitem ca parametru sau să o instanțiem manual. |
| - | Dispunerea componentelor interfeței este de mai multe feluri: | + | |
| - | * dispunere secvențială; | + | |
| - | * dispunere tabelară; | + | |
| - | * dispunere marginală; | + | |
| - | * dispunere tabelară neproporțională. | + | |
| - | </note> | + | |
| - | === 3. Crearea ferestrelor === | + | <code java> |
| + | public void modifyValue (int x) { | ||
| + | SingletonClass.getInstance().value = x; | ||
| + | // se modifica valoarea lui value din clasa | ||
| + | } | ||
| - | == 3.1 Clasa JFrame == | + | SingletonClass.getInstance().show(); |
| + | </code> | ||
| - | Clasa **JFrame** este cea pe care o vom folosi pentru a crea ferestre. Ca orice altă clasă care reprezintă componente Swing ea se află în pachetul //javax.swing//. | + | <note warning> |
| - | + | Singleton poate fi dezavantajos la testare, deoarece leagă dependențe între clase și îngreunează izolarea acestora. | |
| - | Pentru că este un container, vom folosi, de cele mai multe ori, această clasă prin moștenire nu prin instanțiere. Altfel spus, vom crea clase care să reprezinte ferestre și pentru ca acestea să devină ferestre de tip JFrame ele vor moșteni această clasă. | + | De asemenea, varianta lazy nu este thread-safe în multithreading; în astfel de situații se preferă eager instantiation (sau alte variante thread-safe). |
| + | </note> | ||
| <code java> | <code java> | ||
| - | public class Fereastra extends JFrame { | + | public class SingletonClass { |
| - | private JButton button; | + | private static SingletonClass obj = new SingletonClass(); |
| - | + | private SingletonClass() {} | |
| - | public Fereastra(String text) { | + | |
| - | super(text); | + | |
| - | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | + | |
| - | setMinimumSize(new Dimension(300, 200)); | + | |
| - | getContentPane().setBackground(Color.blue); | + | |
| - | setLayout(new SpringLayout()); | + | |
| - | button = new JButton("Apasa"); | + | |
| - | add(button); | + | |
| - | show(); | + | |
| - | pack(); | + | |
| - | } | + | |
| - | public static void main(String args[]) { | + | // eager instantiation - merge la threaduri |
| - | Fereastra f = new Fereastra("Laborator POO"); | + | public static SingletonClass getInstance() { |
| + | return obj; | ||
| } | } | ||
| } | } | ||
| </code> | </code> | ||
| - | <note important> | + | === Utilizări === |
| - | Metoda //add(Component c)// este folosită pentru a adăuga pe fereastră o componentă exact ca în cazul Applet-urilor. Metoda //add()// este moștenită din clasa **Container**. | + | |
| - | </note> | + | |
| - | === 4. Crearea butoanelor === | + | Utilizări frecvente: |
| - | == 4.1 Clasa JButton == | + | * înlocuirea variabilelor globale (instanța Singleton este „globală"); |
| + | * obiecte care reprezintă resurse partajate (de exemplu logger); | ||
| + | * implementarea de Factory (vezi mai jos). | ||
| - | Un buton poate fi creat folosind clasa **JButton**. De obicei, butonul este construit folosind unul dintre constructorii: | + | == 1.2 Factory Pattern == |
| - | * //public JButton();// → un buton fără text | + | === Descriere === |
| - | * //public JButton(String text)// → un buton cu text dat ca parametru | + | |
| - | * //public JButton(String text, Icon ico)// → buton cu text și imagine | + | |
| - | Textul de pe buton poate fi modificat folosind metoda //setText(String text)// sau poate fi preluat folosind metoda //getText()//. | + | Uneori suntem nevoiți să creăm obiecte în funcție de preferința utilizatorului sau de alte necesități. |
| + | De aceea folosim **Factory**, prin care alcătuim o familie de clase înrudite (prin moștenirea aceleiași clase abstracte sau implementarea aceleiași interfețe), | ||
| + | iar crearea obiectului concret este delegată către o metodă de tip factory. | ||
| - | <note warning> | + | {{:poo:breviare:factory_pattern_uml_diagram.jpg?500|}} |
| - | Metodele //setLabel()// și //getLabel()// sunt considerate obsolete și nu se mai folosesc în prezent. | + | |
| - | </note> | + | |
| - | == 4.2 Exemplu de implementare == | + | === Exemplu (pizzas) === |
| + | |||
| + | În exemplul de mai jos, utilizatorul cere un tip de pizza prin nume; dacă tipul există, primește informații despre pizza. | ||
| <code java> | <code java> | ||
| - | class Button extends JFrame implements ActionListener { | + | interface IPizza { |
| - | private JButton button; | + | void showStuff(); |
| + | } | ||
| - | public Button(String text) { | + | /* |
| - | super(text); | + | nu este neaparat sa avem o clasa abstracta ce implementeaza o interfata |
| - | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | + | putem avea pur si simplu o clasa abstracta (fara sa implementeze o interfata) |
| - | setMinimumSize(new Dimension(300, 200)); | + | care e extinsa de clasele normale sau o interfata ce e implementata direct de |
| - | getContentPane().setBackground(Color.blue); | + | clasele normale din Factory |
| - | setLayout(new SpringLayout()); | + | */ |
| - | button = new JButton("Apasa"); | + | abstract class Pizza implements IPizza { |
| - | button.addActionListener(this); | + | public abstract void showStuff(); |
| - | add(button); | + | } |
| - | show(); | + | |
| - | pack(); | + | class PizzaMargherita extends Pizza { |
| + | public void showStuff() { | ||
| + | System.out.println("Sos tomat si branza Mozzarella."); | ||
| } | } | ||
| + | } | ||
| - | public static void main(String args[]) { | + | class PizzaQuattroStagioni extends Pizza { |
| - | Button b = new Button("LaboratorPOO"); | + | public void showStuff() { |
| + | System.out.println("Sos tomat, branza Mozzarella, sunca, pepperoni, " + | ||
| + | "ciuperci, ardei. "); | ||
| } | } | ||
| + | } | ||
| - | @Override | + | class PizzaPepperoni extends Pizza { |
| - | public void actionPerformed(ActionEvent e) { | + | public void showStuff() { |
| - | /* | + | System.out.println("Sos tomat, branza Mozzarella, dublu pepperoni."); |
| - | JButton button = (JButton)e.getSource(); | + | } |
| - | if (button.getText().equals("Apasa")) | + | } |
| - | // valabil dacă aveam mai multe butoane ascultate de acest ascultător | + | |
| - | */ | + | class PizzaHawaii extends Pizza { |
| - | System.out.println("Butonul a fost apasat!"); | + | public void showStuff() { |
| + | System.out.println("Sos tomat, branza Mozzarella, sunca, dublu ananas."); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | class PizzaFactory { | ||
| + | public static Pizza factory (String pizzaName) { | ||
| + | if (pizzaName.equals("Margherita")) | ||
| + | return new PizzaMargherita(); | ||
| + | if (pizzaName.equals("Hawaii")) | ||
| + | return new PizzaHawaii(); | ||
| + | if (pizzaName.equals("Quattro Stagioni")) | ||
| + | return new PizzaQuattroStagioni(); | ||
| + | if (pizzaName.equals("Pepperoni")) | ||
| + | return new PizzaPepperoni(); | ||
| + | return null; | ||
| } | } | ||
| } | } | ||
| </code> | </code> | ||
| - | <note important> | + | == 1.3 Builder Pattern == |
| - | Din moment ce butonul reprezintă o componentă, poate fi adăugat pe un container folosind metoda //add(Component c)// a containerului. | + | |
| - | Butonul **JButton** este sensibil la evenimente de tip **ActionEvent**, așadar, modalitatea de atașare a ascultătorilor și de creare evenimente este similară butoanelor Button din pachetul //java.awt//. | + | === Descriere === |
| - | </note> | + | |
| - | === 5. Crearea componentelor text === | + | Acest pattern este folosit în restaurantele de tip fast food care furnizează meniul pentru copii. |
| + | Un meniu pentru copii constă de obicei într-un fel principal, unul secundar, o băutură și o jucărie. | ||
| + | Pot exista variații în ceea ce privește conținutul meniului, dar procesul de creare este același. | ||
| + | Fie că la felul principal se alege un hamburger sau un cheeseburger, procesul va fi același. | ||
| + | Vânzătorul le va indica celor din spate ce să pună pentru fiecare fel de mâncare, pentru băutură și jucărie. | ||
| + | Toate acestea vor fi puse într-o pungă și servite clienților. | ||
| - | == 5.1 Tipuri de componente text == | + | {{:poo:breviare:img.jpg?500|}} |
| - | Vom folosi trei tipuri de componente text: **JTextField**, **JTextArea** și **JPasswordField**. | + | Acest șablon realizează **separarea construcției de obiecte complexe de reprezentarea lor** astfel încât |
| + | același proces să poată crea diferite reprezentări. Builder-ul creează părți ale obiectului complex | ||
| + | de fiecare dată când este apelat și reține toate stările intermediare. Când produsul este terminat, | ||
| + | clientul primește rezultatul de la builder. | ||
| - | * **JTextField** - este un câmp de text cu un singur rând pe care pot încăpea mai multe caractere. În general, această componentă este folosită pentru a introduce un text de dimensiuni mici; | + | În acest mod, se obține un control mai mare asupra procesului de construcție de noi obiecte. |
| - | * **JTextArea** - este un câmp de text care permite introducerea unui text pe mai multe rânduri, deci, această componentă este folosită pentru texte de dimensiuni mai mari; | + | Spre deosebire de alte pattern-uri din categoria creational, care creau produsele într-un singur pas, |
| - | * **JPasswordField** - este similară componentei JTextField, doar că aceasta ascunde caracterele introduse de utilizator ca în cazul unui câmp pentru introducerea parolei obișnuit. | + | pattern-ul **Builder construiește un produs pas cu pas** la comanda coordonatorului. |
| - | <note tip> | + | === Exemplu (User cu atribute required și optional) === |
| - | Metoda folosită pentru preluarea textului dintr-o componentă text este: //getText()// care returnează o instanță de **String**. | + | |
| - | Pentru a modifica textul dintr-un câmp de text, se folosește metoda //setText(String text)//. | + | <code java> |
| + | public class User { | ||
| + | private final String firstName; // required | ||
| + | private final String lastName; // required | ||
| + | private final int age; // optional | ||
| + | private final String phone; // optional | ||
| + | private final String address; // optional | ||
| - | Componenta **JTextArea** are în comportament și metoda //append(String text)// care permite adăugarea unui text la componentă. | + | private User(UserBuilder builder) { |
| - | </note> | + | this.firstName = builder.firstName; |
| + | this.lastName = builder.lastName; | ||
| + | this.age = builder.age; | ||
| + | this.phone = builder.phone; | ||
| + | this.address = builder.address; | ||
| + | } | ||
| - | == 5.2 Exemplu de implementare == | + | public String getFirstName() { |
| + | return firstName; | ||
| + | } | ||
| - | <code java> | + | public String getLastName() { |
| - | class Text extends JFrame implements ActionListener { | + | return lastName; |
| - | private JButton button; | + | } |
| - | private JTextField user; | + | |
| - | private JPasswordField pass; | + | |
| - | public Text(String text) { | + | public int getAge() { |
| - | super(text); | + | return age; |
| - | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | + | |
| - | setMinimumSize(new Dimension(300, 200)); | + | |
| - | getContentPane().setBackground(Color.blue); | + | |
| - | setLayout(new FlowLayout()); | + | |
| - | button = new JButton("Apasa"); | + | |
| - | button.addActionListener(this); | + | |
| - | add(button); | + | |
| - | user = new JTextField(15); | + | |
| - | add(user); | + | |
| - | pass = new JPasswordField(15); | + | |
| - | add(pass); | + | |
| - | show(); | + | |
| - | pack(); | + | |
| } | } | ||
| - | public static void main(String args[]) { | + | public String getPhone() { |
| - | Text b = new Text("LaboratorPOO"); | + | return phone; |
| } | } | ||
| - | @Override | + | public String getAddress() { |
| - | public void actionPerformed(ActionEvent e) { | + | return address; |
| - | /* | + | |
| - | JButton button = (JButton)e.getSource(); | + | |
| - | if (button.getText().equals("Apasa")) | + | |
| - | // valabil dacă aveam mai multe butoane ascultate de acest ascultător | + | |
| - | */ | + | |
| - | System.out.println(user.getText() + pass.getText()); | + | |
| } | } | ||
| - | } | ||
| - | </code> | ||
| - | === 6. Butoane de selecție === | + | public String toString() { |
| + | return "User:" + this.firstName + " " + this.lastName + " " + | ||
| + | this.age + " " + this.phone + " " + this.address; | ||
| + | } | ||
| - | == 6.1 JCheckBox și JRadioButton == | + | public static class UserBuilder { |
| + | private final String firstName; | ||
| + | private final String lastName; | ||
| + | private int age; | ||
| + | private String phone; | ||
| + | private String address; | ||
| - | Clasele **JCheckBox** și **JRadioButton** definesc componente de tip butoane de selecție. | + | public UserBuilder(String firstName, String lastName) { |
| + | this.firstName = firstName; | ||
| + | this.lastName = lastName; | ||
| + | } | ||
| - | Standard, butoanele **JCheckBox** sunt folosite pentru a crea liste de opțiuni de tip //multiple-choice// (din care poți selecta mai multe variante), iar **JRadioButton** pentru crearea de liste de tip //single-choice// (din care se poate selecta o singură opțiune). | + | public UserBuilder age(int age) { |
| + | this.age = age; | ||
| + | return this; | ||
| + | } | ||
| - | <note important> | + | public UserBuilder phone(String phone) { |
| - | Astfel, pentru butoanele **JRadioButton** adăugăm o nouă clasă **ButtonGroup** cu ajutorul căreia precizăm care sunt butoanele din care se selectează o singură opțiune. | + | this.phone = phone; |
| + | return this; | ||
| + | } | ||
| - | **ButtonGroup** definește un grup de butoane. Din butoanele ce aparțin aceluiași grup, nu putem selecta decât o singură opțiune. | + | public UserBuilder address(String address) { |
| - | </note> | + | this.address = address; |
| + | return this; | ||
| + | } | ||
| - | == 6.2 Utilizare == | + | public User build() { |
| + | return new User(this); | ||
| + | } | ||
| + | } | ||
| - | Ambele tipuri de componente se creează similar butoanelor **JButton**. În general, acestea nu sunt folosite cu evenimente și prin verificări ale stărilor acestora (se verifică dacă este sau nu selectat la un anumit eveniment). | + | public static void main(String[] args) { |
| + | User user1 = new User.UserBuilder("Lokesh", "Gupta") | ||
| + | .age(30) | ||
| + | .phone("1234567") | ||
| + | .address("Fake address 1234") | ||
| + | .build(); | ||
| - | Verificarea stării unei astfel de componente se face folosind metoda //isSelected()// care returnează //true// dacă butonul este bifat și //false// dacă nu este bifat. | + | User user2 = new User.UserBuilder("Jack", "Reacher") |
| + | .age(40) | ||
| + | .phone("5655") | ||
| + | //no address | ||
| + | .build(); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||
| - | <note tip> | + | == 1.4 Singleton Factory == |
| - | Pentru o înțelegere mai bună, se recomandă analizarea exemplelor propuse în arhiva laboratorului. | + | |
| - | </note> | + | |
| - | === 7. JScrollPane === | + | O clasă de tip Factory poate fi utilizată în mai multe locuri în cadrul unui proiect. Pentru a economisi resurse, |
| + | putem folosi pattern-ul **Singleton** pentru Factory, astfel încât să existe o singură instanță a clasei Factory. | ||
| - | == 7.1 Descriere == | ||
| - | **JScrollPane** este o componentă folosită pentru adăugarea de bare de defilare pentru o altă componentă care ar putea depăși dimensiunile containerului în care este adăugată. | + | === 2. Behavioral Patterns === |
| - | Instanța JScrollPane nu este folosită în acțiunile directe pe care le are componenta pe care o susține. La construirea instanței, i se dă o componentă pentru care este creată și pe care adaugă bare de defilare (//scrollbars//). | + | == 2.1 Observer Pattern == |
| - | Apoi, instanța **JScrollPane** este adăugată pe container în locul componentei din instanța JScrollPane. | + | === Descriere === |
| - | == 7.2 Exemplu de implementare == | + | Acest design pattern stabilește o relație **one-to-many** între obiecte. |
| + | Avem un obiect numit **subiect**, căruia îi este asociată o colecție (listă) de **observatori**. | ||
| + | Observatorii sunt obiecte dependente de subiect și sunt notificate automat de către subiect atunci când în subiect are loc o acțiune | ||
| + | sau o modificare a stării. | ||
| - | <code java> | + | {{:poo:breviare:observer_breviar.png?500|}} |
| - | class Text extends JFrame { | + | |
| - | private JTextArea textArea; | + | |
| - | private JScrollPane scroll; | + | |
| - | public Text(String text) { | + | == 2.2 Strategy Pattern == |
| - | super(text); | + | |
| - | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | + | |
| - | setMinimumSize(new Dimension(300, 200)); | + | |
| - | getContentPane().setBackground(Color.blue); | + | |
| - | setLayout(new FlowLayout()); | + | |
| - | textArea = new JTextArea(200, 100); | + | |
| - | textArea.setLineWrap(true); | + | |
| - | textArea.setWrapStyleWord(true); | + | |
| - | textArea.setFont(new Font("Tahoma", 2, 12)); | + | |
| - | scroll = new JScrollPane(textArea); | + | |
| - | add(scroll); | + | |
| - | show(); | + | |
| - | pack(); | + | |
| - | } | + | |
| - | public static void main(String args[]) { | + | === Descriere === |
| - | Text b = new Text("LaboratorPOO"); | + | |
| - | } | + | |
| - | } | + | |
| - | </code> | + | |
| - | === 8. Etichete === | + | **Strategy** este un design pattern behavioral ce oferă o familie de algoritmi (strategii), |
| + | încapsulate în clase care oferă o interfață comună de folosire. | ||
| + | Clientul (utilizatorul) poate alege dinamic strategia care va fi folosită. | ||
| - | == 8.1 JLabel == | + | {{:poo:breviare:strategy_breviar.png?500|}} |
| - | O etichetă reprezintă cea mai simplă componentă. Aceasta este folosită pentru afișarea unui text static în cele mai multe cazuri. | + | Exemplu de motivare: la căutarea unui element într-o colecție, putem alege algoritmul în funcție de proprietăți ale colecției |
| + | (de exemplu, dacă este sortată: căutare binară; altfel: iterare liniară). | ||
| - | Textul de pe o etichetă poate fi modificat sau preluat folosind metodele //getText()// și //setText(String text)//. | + | == 2.3 Visitor Pattern == |
| - | <note tip> | + | === Descriere === |
| - | Un **JLabel** poate fi uzitat și pentru afișarea unei imagini. În acest caz, nu i se aplică niciun text, ci doar un **ImageIcon**, această modalitate fiind considerată cea mai simplă de a afișa o imagine într-un container. | + | |
| - | </note> | + | |
| - | === 9. Tratarea evenimentelor === | + | Acest design pattern oferă posibilitatea de a separa un algoritm de structura de date pe care acesta operează, |
| + | astfel încât să putem adăuga ușor funcții noi care operează peste o familie de clase fără să modificăm structura acestora. | ||
| - | == 9.1 Ce sunt evenimentele? == | + | Pe scurt, folosim **Visitor** dacă avem tipuri diferite și dorim să adăugăm/schimbăm operații fără să modificăm clasele. |
| - | Un **eveniment** este produs de o acțiune a utilizatorului asupra unei componente grafice și reprezintă mecanismul prin care utilizatorul comunică efectiv cu programul. | + | {{:poo:breviare:visitor.jpg?500|}} |
| - | Exemple de evenimente sunt: | + | În cadrul pattern-ului: |
| - | * apăsarea unui buton; | + | |
| - | * modificarea textului într-un control de editare; | + | |
| - | * închiderea sau redimensionarea unei ferestre. | + | |
| - | <note important> | + | * avem o interfață **Visitor**, care reprezintă operația aplicată; |
| - | Componentele care generează anumite evenimente se mai numesc și **surse de evenimente**. | + | * avem o interfață/clasă abstractă **Visitable** (numită în unele scheme **Element**), care reprezintă obiectele peste care se aplică operațiile; |
| - | </note> | + | * Visitor are metode de forma `visit(...)`; |
| + | * Visitable are metoda `accept(Visitor v)`. | ||
| - | == 9.2 Listeners (Ascultători de evenimente) == | + | === Exemplu (Ls/Cat peste Repository: Director/Fisier) === |
| - | Interceptarea evenimentelor generate de componentele unui program se realizează prin intermediul unor clase de tip **listener** (ascultător, consumator de evenimente). | + | <code java> |
| + | interface Visitor { | ||
| + | void visit (Director f); | ||
| + | void visit (Fisier f); | ||
| + | } | ||
| - | În Java, orice obiect poate "consuma" evenimente, cu condiția ca acesta să implementeze interfața listener corespunzătoare tipului de eveniment pe care dorește să-l intercepteze. | + | class Ls implements Visitor { |
| + | public void visit (Director f) { | ||
| + | System.out.println(f.getName()); | ||
| + | for (Repository repo: f.getChildren()) { | ||
| + | System.out.println("\t" + repo.getName()); | ||
| + | // afisam numele unui repo (fisier / folder) | ||
| + | } | ||
| + | } | ||
| + | |||
| + | public void visit (Fisier f) { | ||
| + | System.out.println("Not a folder"); | ||
| + | /* comanda Ls (in acest exemplu) este specifica doar folderelor, | ||
| + | in acest caz este evidentiat un dezavantaj al Visitor-ului, | ||
| + | faptul ca noi trebuie sa implementam metode de care nu avem nevoie | ||
| + | in acest caz - se incalca Interface Segregation Principle */ | ||
| + | } | ||
| + | } | ||
| + | |||
| + | class Cat implements Visitor { | ||
| + | public void visit (Director f) { | ||
| + | // avertisment ca avem folder, nu fisier | ||
| + | } | ||
| + | public void visit (Fisier f) { | ||
| + | // citire fisier, folosind numele fisierului | ||
| + | } | ||
| + | } | ||
| + | |||
| + | abstract class Repository { | ||
| + | private String name; | ||
| + | // numele unui fisier sau folder (de fapt, calea acestuia) | ||
| + | public String getName() { | ||
| + | return name; | ||
| + | } | ||
| + | public abstract void accept (Visitor f); | ||
| + | } | ||
| + | |||
| + | class Fisier extends Repository { | ||
| + | public void accept (Visitor f) { | ||
| + | f.visit(this); | ||
| + | // Visitor-ul "viziteaza" fisierul, adica acesta | ||
| + | // efectueaza o operatie asupra fisierului | ||
| + | } | ||
| + | } | ||
| + | |||
| + | class Director extends Repository { | ||
| + | private List<Repository> children = new ArrayList<>(); | ||
| + | public List<Repository> getChildren() { | ||
| + | return children; | ||
| + | } | ||
| + | public void accept (Visitor f) { | ||
| + | f.visit(this); | ||
| + | } | ||
| + | } | ||
| + | </code> | ||