Differences

This shows you the differences between two versions of the page.

Link to this comparison view

poo:breviare:breviar-11 [2020/12/16 07:20]
mihai.nan [Breviar 11]
poo:breviare:breviar-11 [2025/12/14 17:41] (current)
george.tudor1906
Line 1: Line 1:
- 
 ====== Breviar 11 ====== ====== Breviar 11 ======
  
 +=== Introducere în Design Patterns ===
 +
 +== 1. Ce reprezintă design patterns? ==
 +
 +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.
 +
 +== 2. Tipuri de design patterns ==
 +
 +Există 3 tipuri de design patterns, în funcție de aspectul și de funcționalitatea obiectelor:
 +
 +  * **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).
 +
 +=== 1. Creational Patterns ===
 +
 +== 1.1 Singleton Pattern ==
 +
 +=== Descriere ===
 +
 +Uneori ne dorim să avem un obiect care să apară doar o singură dată într-o aplicație (de exemplu conducătorul unei țări).
 +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.
 +
 +Pentru a asigura restricționarea:​
 +
 +  * 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).
 +
 +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).
 +
 +<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;
 +
 +    public int value = 10;
 +
 +    // lasam constructorul clasei privat pentru a nu fi accesat din exterior
 +    private SingletonClass() {
 +        // do stuff
 +        System.out.println("​Instantiam!"​);​
 +    }
 +
 +    // 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;
 +    }
 +
 +    public void show() {
 +        System.out.println("​Singleton is magic"​);​
 +    }
 +}
 +</​code>​
 +
 +=== Avantaje / Dezavantaje ===
 +
 +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.
 +
 +<code java>
 +public void modifyValue (int x) {
 +    SingletonClass.getInstance().value = x;
 +    // se modifica valoarea lui value din clasa
 +}
 +
 +SingletonClass.getInstance().show();​
 +</​code>​
 +
 +<note warning>
 +Singleton poate fi dezavantajos la testare, deoarece leagă dependențe între clase și îngreunează izolarea acestora.
 +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>
 +public class SingletonClass {
 +    private static SingletonClass obj = new SingletonClass();​
 +    private SingletonClass() {}
 +
 +    // eager instantiation - merge la threaduri
 +    public static SingletonClass getInstance() {
 +        return obj;
 +    }
 +}
 +</​code>​
 +
 +=== Utilizări ===
 +
 +Utilizări frecvente:
 +
 +  * înlocuirea variabilelor globale (instanța Singleton este „globală"​);​
 +  * obiecte care reprezintă resurse partajate (de exemplu logger);
 +  * implementarea de Factory (vezi mai jos).
 +
 +== 1.2 Factory Pattern ==
 +
 +=== Descriere ===
 +
 +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.
 +
 +{{:​poo:​breviare:​factory_pattern_uml_diagram.jpg?​500|}}
 +
 +=== 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>
 +interface IPizza {
 +    void showStuff();​
 +}
 +
 +/*
 +nu este neaparat sa avem o clasa abstracta ce implementeaza o interfata
 +putem avea pur si simplu o clasa abstracta (fara sa implementeze o interfata)
 +care e extinsa de clasele normale sau o interfata ce e implementata direct de
 +clasele normale din Factory
 +*/
 +abstract class Pizza implements IPizza {
 +    public abstract void showStuff();​
 +}
 +
 +class PizzaMargherita extends Pizza {
 +    public void showStuff() {
 +        System.out.println("​Sos tomat si branza Mozzarella."​);​
 +    }
 +}
 +
 +class PizzaQuattroStagioni extends Pizza {
 +    public void showStuff() {
 +        System.out.println("​Sos tomat, branza Mozzarella, sunca, pepperoni, " +
 +                           "​ciuperci,​ ardei. ");
 +    }
 +}
 +
 +class PizzaPepperoni extends Pizza {
 +    public void showStuff() {
 +        System.out.println("​Sos tomat, branza Mozzarella, dublu pepperoni."​);​
 +    }
 +}
 +
 +class PizzaHawaii extends Pizza {
 +    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>​
 +
 +== 1.3 Builder Pattern ==
 +
 +=== Descriere ===
 +
 +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.
 +
 +{{:​poo:​breviare:​img.jpg?​500|}}
 +
 +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.
 +
 +În acest mod, se obține un control mai mare asupra procesului de construcție de noi obiecte.
 +Spre deosebire de alte pattern-uri din categoria creational, care creau produsele într-un singur pas,
 +pattern-ul **Builder construiește un produs pas cu pas** la comanda coordonatorului.
 +
 +=== Exemplu (User cu atribute required și optional) ===
 +
 +<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
 +
 +    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 String getFirstName() {
 +        return firstName;
 +    }
 +
 +    public String getLastName() {
 +        return lastName;
 +    }
 +
 +    public int getAge() {
 +        return age;
 +    }
 +
 +    public String getPhone() {
 +        return phone;
 +    }
 +
 +    public String getAddress() {
 +        return address;
 +    }
 +
 +    public String toString() {
 +        return "​User:"​ + this.firstName + " " + this.lastName + " " +
 +               ​this.age + " " + this.phone + " " + this.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();
 +    }
 +}
 +</​code>​
 +
 +== 1.4 Singleton Factory ==
 +
 +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.
 +
 +
 +=== 2. Behavioral Patterns ===
 +
 +== 2.1 Observer Pattern ==
 +
 +=== Descriere ===
 +
 +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.
 +
 +{{:​poo:​breviare:​observer_breviar.png?​500|}}
 +
 +== 2.2 Strategy Pattern ==
 +
 +=== Descriere ===
 +
 +**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ă.
 +
 +{{:​poo:​breviare:​strategy_breviar.png?​500|}}
 +
 +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ă).
 +
 +== 2.3 Visitor Pattern ==
 +
 +=== Descriere ===
 +
 +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.
 +
 +Pe scurt, folosim **Visitor** dacă avem tipuri diferite și dorim să adăugăm/​schimbăm operații fără să modificăm clasele.
 +
 +{{:​poo:​breviare:​visitor.jpg?​500|}}
 +
 +În cadrul pattern-ului:​
 +
 +  * avem o interfață **Visitor**,​ care reprezintă operația aplicată;
 +  * avem o interfață/​clasă abstractă **Visitable** (numită în unele scheme **Element**),​ care reprezintă obiectele peste care se aplică operațiile;​
 +  * Visitor are metode de forma `visit(...)`;​
 +  * Visitable are metoda `accept(Visitor v)`.
 +
 +=== Exemplu (Ls/Cat peste Repository: Director/​Fisier) ===
 +
 +<code java>
 +interface Visitor {
 +    void visit (Director f);
 +    void visit (Fisier f);
 +}
 +
 +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
 +    }
 +}
  
-<​HTML>​ +abstract class Repository { 
-  <​iframe src="​https:​//docs.google.com/​file/​d/​1Y2H7korhd2qB0r49upMLef3mhTz2AVy-/​preview"​ width="​640"​ height="​720"></​iframe>​ +    ​private String name; 
-</​HTML>​+    ​// 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>​
  
poo/breviare/breviar-11.1608096000.txt.gz · Last modified: 2020/12/16 07:20 by mihai.nan
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