CURS ACS 1.clean Code 2.design Patterns
CURS ACS 1.clean Code 2.design Patterns
CLEAN CODE
1. De ce Clean Code?
Codul trebuie sa fie ușor de citit, ușor de înțeles, ușor de modificat de către oricine
2. Principii
1. D.R.Y ( Don’t Repeat Yourself)
Aplicabil ori de câte ori dăm Copy/Paste unei bucăți de cod
Daca noi modif o sectiune de cod care a fost copiat si in alta parte, s-ar putea sa uitamsa modif peste tot pe unde
am dat paste
Trb sa urmam Single Responsibility Principle : incurajeaza reutil. Codului in alte prog, nu repetitia lui in acelasi prog
Recomandari: metode sau clase diverse
3. Naming conventions
UpperCamelCase • lowerCamelCase • System Hungarian Notation • Apps Hungarian Notation
1. Clase : substantiv specific, fără prefixe și sufixe inutile
2. Metode: daca contine conjuctii=> sugereaza ca trb sa o impartim in mai multe met
3. Variabile: Nu e indicat ca variabilele de tip șiruri de caractere să conțină cod din alte limbaje (SQL, CSS)
Variabilele booleane trebuie să sune ca o întrebare la care se poate răspunde cu adevărat/fals boolean
isTerminated = false;
8. Dictionar
Test Driven Development (TDD) – Dezvoltare bazată pe cazuri de utilizare
Refactoring – rescrierea codului într-o manieră ce se adaptează mai bine noilor specificații
Automatic Testing (Unit Testing) – Testarea automată a codului pe baza unor cazuri de utilizare. Foarte
utilă în refactoring pentru că putem verifica dacă am păstrat toate funcționalitățile sau nu (regression)
Code review – Procedură întâlnită în special în AGILE (XP, SCRUM) ce presupune ca orice bucată de cod
scrisă să fie revizuită și de un alt programator
Pair programming – Tehnică specifică AGILE prin care programatorii lucrează pe perechi pentru task-uri
complexe, pentru a învăța sau pentru a evita code review
CURS 2. DESIGN PATTERNS
3. Design pattern
Un pattern reprezintă o soluție reutilizabila pentru o problema standard, într-un anumit context
Facilitează reutilizarea arhitecturilor si a design-ului software
NU sunt structuri de date
3.1 Avantaje
Permit reutilizarea soluțiilor standard la nivel de cod sursa/arhitectura
• Permit documentarea codului sursa/arhitecturilor
• Permit înțelegerea mai facila a codului sursa/a arhitecturii
• Reprezintă concepte universal cunoscute - definesc un vocabular comun
• Sunt soluții testate si foarte bine documentate
3.2. Componente
3.2.1. Nume:
Rezultate
Avantaje si dezavantaje
3.3. Utilizare
Observer in Java AWT si Swing pentru callback-uri
Iterator in C++ STL si Java Collections
Façade in multe librarii Open-Source pentru a ascunde complexitatea rutinelor interne
Bridge si Proxy in framework-uri pentru aplicatii distribuite
Singleton in Hybernate si NHybernate
Distribuția responsabilității
Interacțiunea intre clase si obiecte
3.4.3.1. Chain of Responsibility: Gest. tratarea unui eveniment de catre mai multi furnizori de solutii
3.4.3.2. Command: Request or Action is first-class object, hence re-storable
3.4.3.3. Iterator: Gestioneaza parcurgerea unei colectii de elemente
3.4.3.4. Interpreter: Intepretor pentru un limbaj cu o gramatica simpla
3.4.3.5. Mediator: Coordoneaza interactiunea dintre mai multi asociati
3.4.3.6. Memento: Salvazeaza si restaureaza starea unui obiect
3.4.3.7. Observer: Defineste un hadler pentru diferite evenimente
3.4.3.8. State: Gestioneaza obiecte al caror comportament depinde de starea lor
3.4.3.9. Strategy: Incapsuleaza diferiti algoritmi
3.4.3.10. Template Method: Incapsuleaza un algoritm ai carui pasi depend de o clasa derivate
3.4.3.11. Visitor: Descrie metode ce pot fi aplicate pe o structura neomogena
4. Creational Design Patterns
4.1.Modelul SINGLETON
Problema: Se dorește crearea unei singure instanțe pentru o clasă prin care să fie gestionată o
resursă/un eveniment în mod centralizat;
Soluția: se bazează pe existența unei singure instanțe ce poate fi creata o singură dată dar care poate
fi referită de mai multe ori;
Diagrama
Componente:
Avantaje:
• Gestiune centralizata a unei resurse printr-o instanță unică
• Controlul strict al instanțierii unei clase – o singura data
• Nu permite duplicarea instanțelor
• Ușor de implementat
• Lazy instantiation – obiectul este creat atunci când este necesar
Dezavantaje:
In multi-threading pot apărea probl de sincronizare sau cooperare daca singleton-ul este partajat
Poate deveni un bottleneck care sa afecteze performanta aplicației
Scenarii
Problema: implementarea unui mecanism centralizat prin care crearea obiectelor este transparenta
pentru client; prin interfața publică clientul știe cum să creeze obiecte însă nu știe cum este
implementat acest lucru;
Soluția: poate să fie extinsă prin adăugarea de noi tipuri concrete de obiecte fără a afecta codul
existent;
• complexitatea creării obiectelor este ascunsa clientului;
• obiectele sunt referite printr-o interfață comună;
clase concrete reprezintă o familie de obiecte definită în jurul interfeței comune;
• eliminarea dependenței codului clientului de crearea efectivă a obiectelor utilizate în soluție;
Componente:
Componente:
Avantaje:
Dezavantaje:
Problema: Se dorește implementarea unui mecanism prin care crearea obiectelor este transparenta
pentru client
Soluția: poate să fie extinsă prin adăugarea de noi tipuri concrete de obiecte fără a afecta codul scris
• Obiectele sunt referite printr-o interfață comună și nu direct.
Componente:
• InterfataFactory: interfață ce definește metodele abstracte pentru crearea de instanțe
• InterfataProdusA/InterfataProdusB: interfețe ce definesc tipurile abstracte de ob ce pot fi create
• FactoryConcretA/FactoryConcretB: clase concrete ce implementează interfața si metodele prin
care sunt create obiecte de tipul Product
• ProduseTipA, ProduseTipB,…:clase concrete ce definesc diferitele tipuri de obiecte ce pot fi create
Exemplu:
Avantaje:
Dezavantaje:
Toate pattern-urile Factory promovează loose coopling si sunt bazate pe Dependency Inversion
Principle
Factory Method
Problema:
Soluția trebuie sa construiască obiecte complexe printr-un mecanism care este independent de
procesul de realizare a obiectelor
Clientul construiește obiectele complexe specificând doar tipul si valoarea sa, fără a cunoaște
detaliile interne ale obiectului (cum stochează si reprezintă valorile)
Procesul de construire a obiectelor trebuie sa poata fi utilizat pentru a defini obiecte diferite din
aceeași familie
Obiectele sunt gestionate prin interfața comuna
Instanța de tip Builder construiește obiectul însă tipul acestuia este definit de subclase
Componente:
AbstractBuilder: interfața abstracta ce definește metodele prin care sunt construite parti ale
obiectului complex
Builder: clasa concreta ce construiește părțile si pe baza lor obiectul final
Produs: clasa abstracta ce definește obiectul complex ce este construit
Director: clasa concreta ce construiește obiectul complex utilizând interfața de tip Builder
Avantaje:
Obiectele complexe pot fi create independent de părțile care îl compun (un obiect poate sa le
conțină pe toate sau doar o parte)
Sistemul permite reprezentarea diferita a obiectelor create printr-o
interfață comună
Algoritmul de creare a obiectului este flexibil deoarece clientul alege
ce părți sa fie create
Dezavantaje:
Scenariu:
ACME Inc. dorește să dezvolte un joc 3D pentru dispozitive Android utilizând un engine propriu. Cele 2
modele 3D pentru caractere sunt destul de complexe și generarea lor are impact asupra timpului de
procesare și implicit asupra duratei de viață a acumulatorului. Același model este utilizat de mai multe
ori pentru a popula o scena cu personaje. Trebuie găsită o soluție eficientă prin care scenele să fie
încărcate rapid.
Problema:
Implementare:
In Java implementarea implicită pentru clone() este Shallow Copy, dar explicit putem face si Deep
Copy
Avantaje:
Dezavantaje:
Scenariu:
ACME Inc. dorește să cumpere un nou framework pentru serviciile din back-end. Interfața pentru aceste
servicii gestionează datele prin intermediul obiectelor de tip ACME, iar noul framework procesează
datele prin intermediul obiectelor de tip MICRO. Programatorii companiei trebuie sa găsească o soluție
de a integra cele doua framework-uri fără a le modifica.
Problema:
Componente:
Avantaje:
Clasele existente (la client si la furnizor) nu sunt modif pentru a putea fi folosite într-un alt context
Se adaugă doar un layer intermediar Pot fi definite cu ușurință adaptoare pentru orice context
Dezavantaje:
Adaptorul de clase se bazează pe derivare multipla, lucru care nu este posibil in Java. Alternativa
este prin interfețe si compunere
5.2.Modelul FAÇADE (Wrapper)
Scenariu:
ACME Inc. dezvoltă o soluție software pentru managementul unei locuințe inteligente. Includerea în
framework a tuturor componentelor controlabile dintr-o astfel de locuință (ferestre, încălzire, alarma,
etc) a generat un număr mare de clase. Departamentul care dezvolta interfața Web a soluției oferă un
set minim de funcții ce pot fi controlate de la distanta. Deși funcționalitatea este simpla, numărul mare
de clase ce se instanțiază și a metodelor apelate îngreunează dezvoltarea si testarea. In acest sens, o
interfață mai simpla ar ajuta acest departament.
Problema:
Soluția conține o mulțime de clase iar execuția unei funcții presupune apeluri multiple de metode
aflate in aceste clase
Clasele nu se modifica însă se construiește un layer intermediar ce permite apelul/gestiunea facila
a metodelor din mai multe interfețe
Utilă in situația in care framework-ul creste in complexitate si nu este posibila rescrierea lui pentru
simplificare
Apelurile către multiplele interfețe sunt mascate de aceasta interfață comună
Componente:
• Clasa1, Clasa2, …, Package1, Package2, …:
clase existente ce pun la dispoziție diferite
interfețe;
• Facade: Definește o interfața simplificata
pentru contextul existent;
• Client: Reprezintă framework-ul care
apelează interfața specifica noului domeniu
Avantaje:
Framework-ul nu se rescrie
Se adaugă doar un layer intermediar ce ascunde complexitatea framework-ului din spate
Pot fi definite cu ușurință metode care sa simplifice orice situație
Implem. principiul Least Knowledge – reducerea interacț. intre ob la nivel de “prieteni apropriați”
Dezavantaje:
Problema:
Extinderea (decorarea) statica sau la run-time a funcționalității sau stării unor obiecte, independent
de alte instanțe ale aceleiași clase
Obiectul poate sa fie extins prin aplicarea mai multor decoratori
Clasa existenta nu trebuie sa fie modificata
Utilizarea unei abordări tradiționale, prin derivarea clasei, duce la ierarhii complexe ce sunt greu de
gestionat. Derivarea adaugă comportament nou doar la compilare
Componente:
Avantaje:
Dezavantaje:
Un decorator este un wrapper pentru obiectul inițial. El nu este identic cu obiectul încapsulat
Utilizarea excesiva generează o mulțime de obiecte care arata la fel dar care se comporta diferit –>
dificil de înțeles si verificat codul
Situația trebuie analizata cu atenție deoarece in unele situații patternul Strategy este mai indicat
Comparatie:
Adapter – asigură o interfață diferită obiectului
Facade – asigură o interfață simplificată obiectului
Decorator – asigură o interfață îmbunătățită obiectului
5.4.Modelul Composite
Scenariu:
ACME Inc. dezvoltă o soluție software pentru managementul resurselor umane dintr-o companie.
Soluția trebuie să ofere un mecanism unitar care să centralizeze angajații companiei și care să țină cont
de:
relațiile ierarhice
apartenența angajaților la un departament
rolurile diferite ale angajaților
setul comun de funcții pe care un angajat le poate îndeplini
Problema:
Componente:
Framework-ul nu se rescrie
Permite gestiunea facila a unor ierarhii de clase ce conțin atât primitive cat si obiecte compuse
Codul devine mai simplu deoarece obiectele din ierarhie sunt tratate unitar
Adăugarea de noi componente care respecta interfața comună nu ridica probleme suplimentare
5.5.Modelul Flyweight
ACME Inc. dezvolta un editor de texte ca soluție alternativa la soluțiile cunoscute. In faza de testare s-a
observat ca pe măsura ce crește dimensiunea textului, crește și memoria ocupată de această aplicația.
Ritmul de creștere este unul anormal, destul de rapid , iar in final generează întârzieri între momentul
tastării unui caracter si cel al afișării. Teste pe aceasta zona au arătat ca exista o legătura între numărul
de caractere tastate si numărul de obiecte.
Problema:
Soluția generează o mulțime de obiecte cu o structura interna complexa si care ocupa un volum
mare de memorie
Obiectele au atribute comune însă o parte din starea lor variază; memoria ocupata de ele poate fi
minimizata prin partajarea stării fixe intre ele Starea obiectelor poate fi gestionat prin structuri
externe iar numărul de obiecte efectiv create poate fi minimizat
Utilizarea unui obiect înseamnă reîncărcarea stării lui variabile într-un obiect existent
Scenariu: Diagrama:
Componente:
Flyweight: Interfață ce permite obiectelor să primească valori ce fac parte din starea lor si să facă
diferite procesări pe baza acesteia;
FlyweightFactory: Un pattern de tip factory ce construiește si gestionează obiecte de tip flyweight;
o Menține o colecție de obiecte diferite astfel încât ele sa fie create o singură dată
FlyweightConcret: Clasa implementează interfața de tip Flyweight si permite stocarea stării
permanente (ce nu poate fi partajat) a obiectelor
o Valori ce reprezintă o stare temporara partajata între obiecte sunt primite si procesate
prin intermediul metodelor din interfață
Client: Gestionează obiectele de tip flyweight si starea lor temporara
Avantaje:
Se reduce memoria ocupata de obiecte prin partajarea lor intre clienți sau a stării lor intre obiecte
de același tip
Pentru a gestiona corect partajarea obiectelor de tip Flyweight între clienți și fire de execuție,
acestea trebuie sa immutable
Dezavantaje:
Trebuie analizate clasele si contextul pentru a se determina ce reprezintă stare variabilă ce poate fi
internalizată
Efectele sunt vizibile pentru soluții in care numărul de obiecte este mare
Nivelul de memorie redusa depinde de numărul de categorii de obiecte de tip Flyweight
o
Sabloane asemanatoare:
Problema:
Componente:
InterfataEntitate
o Definește interfața obiectului real la care se face conectarea
o Interfața este implementata si de proxy astfel încât să se poată conecta la obiecte
Proxy
o Gestionează referința către obiectul real
o Implementează interfața obiectului real
o Controlează accesul la obiectul real
Entitate
o Obiectul real către care proxy-ul are legătura
Tipuri de proxy:
Virtual Proxies: gestionează crearea si inițializarea unor obiecte costisitoare; acestea pot fi create
doar atunci când e nevoie sau partajează o singura instanță intre mai mulți client;
Remote Proxies: asigura o instanță virtuala locala pentru un obiect aflat la distanta – Java RMI.
Protection Proxies: controlează accesul la metodele unui obiect sau la anumite obiecte.
Smart References: gestionează referințele către un obiect
Sabloane asemanatoare:
6.1.Modelul Strategy
Problema:
Alegerea la run-time a algoritmului/funcției care sa fie utilizata pentru procesarea unor date;
Algoritmul se poate alege pe baza unor condiții descrise la execuție in funcție de contextul datelor
de intrare
Clasa existenta nu trebuie sa fie modificata
Utilizarea unei abordări tradiționale, prin includerea in clasa a tuturor metodelor posibile, duce la
ierarhii complexe ce sunt greu de gestionat. Derivarea adaugă comportament nou doar la compilare
Componente:
Avantaje:
Problema:
Avantaje:
Componente:
Observabil: clasa abstracta ce definește interfața obiectelor gestionează evenimente si care sunt
observabile;
ObservabilConcret: definește obiecte ce permit abonarea unor observatori;
Observator: Interfață ce definește modalitatea in care sunt notificați observatorii;
o Permite gestiunea mai multor observatori
ConcreteDecorator: Implementează funcții concrete care sunt executate in urma notificării;
Metode de comunicare:
2 modele de notificare a observatorului la modificarea stării:
Problema:
Tratarea unui eveniment sau a unui obiect se face diferit in funcție de starea acestuia
Gestiunea tuturor cazurilor ar implica o structură complexă care să verifice toate cazurile particulare
Există legături de dependență între cazurile de utilizare: execuția unui caz poate implica ignorarea
celorlalte sau tratarea următorului caz
Componente:
Problema:
Componente:
Problema:
Aplicația definește acțiuni parametrizabile ce pot fi executate mai târziu fără a solicita clientului
cunoașterea detaliile interne necesare execuției.
Pentru a nu bloca clientul, se dorește ca aceste acțiuni să fie definite și trimise spre execuție fără a
mai fi gestionate de client
Se decuplează execuția întârziată (ulterioara) a unei acțiuni de proprietar. Din punctul acestuia de
vedere, acțiunea a fost deja trimisa spre execuție.
Concept echivalent cu macro-urile. Obiectul de tip command încapsulează toate informațiile
necesare execuției acțiunii mai târziu de către responsabil
Clientul este decuplat de cel ce executa acțiunea
Componente:
Scenariu:
ACME Inc. dezvolta o
soluție software pentru
un restaurant, astfel
încât chelnerul să poată prelua comenzile direct pe telefonul mobil. Comenzile sunt preluate de la client
și ele sunt create pe loc, fiind automat alocat bucătarul specializat pe acel fel de mâncare, ingredientele
folosite si alte cerințe speciale ale clientului. Aceste detalii sunt puse de aplicație, fără a fi necesara
intervenția chelnerului care doar selectează felul de mâncare solicitat. Comenzile sunt trimise
bucătarilor la finalizarea comenzii pentru masa respectiva, urmând să fie executate in funcție de gradul
de încărcare al fiecărui bucătar.
6.6.Modelul Template Method
Problema:
Componente:
Problema:
Componente:
Creaționale:
• Factory – creează obiecte dintr-o familie
• Builder – creează obiecte setând anumite atribute
• Singleton – creează o unică instanță
Structurale:
• Adapter – adaptează un API (o interfață) la altul
• Composite – gestionează o ierarhie de obiecte
• Decorator – atribuie la run-time funcționalitate nouă unui obiect existent
• Façade – simplifica execuția (apelarea) unui scenariu complex
• Flyweight – gestionează eficient mai multe instanțe (clone) ale unui set redus de modele
Comportamentale:
• Strategy – schimba la run-time funcția executată
• Observer – execută o acțiune când are loc un eveniment sau un observabil își schimba starea
• Chain of Responsibility – gestionează o secvență de acțiuni ce pot procesa un eveniment sau un obiect
• Command – gestionează realizarea întârziată a unei acțiuni
• Memento – gestionează stările anterioare ale unui obiect
• State – stabilește tipul acțiunii în funcție de starea obiectului
• Template – gestionează un șablon fix de acțiuni