0
Programare orientata pe obiecte
Paradigma reprezintă un set de concepte, valori, ipoteze şi practici care constituie un mod de percepţie a realităţii comun pentru o anumită comunitate.
Delegare
- principiu cheie al OOP, permite să grupăm un anumit funcţional într-un anumit element.
- Transmiterea responsabilităţilor către alte obiecte;
Chain of responsability
O aplicaţie OOP este structurată ca o comunitate de agenţi care interacţionează, numiţi obiecte. Fiecare obiect are un rol şi oferă un serviciu sau realizează o acţiune care este utilizată de alţi membri ai comunităţii.
O acţiune este iniţiată în aplicaţiile OOP prin transmiterea unui mesaj către un agent, responsabil de acţiune. Mesajul care reprezintă cererea la acţiune este acompaniat de altă informaţie adăugătoare, argumente, parametri, necesari pentru a realiza cererea.
Receptorul este obiectul care primeşte mesajul. Dacă receptorul acceptă mesajul, el acceptă responsabilitatea de a realiza această acţiune. Ca răspuns la mesaj, receptorul execută o metodă pentru a satisface cererea.
Tema: Paradigma POO. Abstracţii
Abstracţie – metodă/proces de eliminare a caracteristicilor numeroase unui obiect pentru a-l reduce la un set de caracteristici generale. În OOP, este unul din cele 3 principii centrale, pe lîngă incapsulare şi moştenire. În procesul de abstractizare, programatorul ascunde datele importante despre obiect pentru a reduce complexitatea şi a mări eficienţa.
Programarea orientata pe obiecte este o metoda de implementare in care programele sunt organizate ca ansamble de obiecte ce coopereaza intre ele, fiecare obiect reprezentand instanta unei clase; fiecare clasa apartine unei ierarhii de clase in cadrul careia clasele sunt legate prin relatii de mostenire.
Aceasta definitie cuprinde trei parti importante, si anume:
• obiectele si nu algoritmii sunt blocurile logice fundamentale;
• fiecare obiect este o instanta a unei clase. Clasa este o descriere a unei multimi de obiecte caracterizate prin structura si comportament similare.
• clasele sunt legate intre ele prin relatii de mostenire.
Principii:
1. Totul este obiect;
2. Obiectele interacţionează prin transmiterea şi primirea mesajelor;
3. Fiecare obiect îşi are memoria proprie;
4. Fiecare obiect aparţine unui grup de obiecte – clasă;
5. Clasa defineşte comportamentul comun tuturor obiectelor – exemplalelor sale;
6. Clasele se organizează într-o structură arborescentă cu o rădăcină comună, asigurîndu-se „Transferul” de comportament de la clasele superioare claselor inferioare din ierarhia de moştenire.
7. Obiectele trebuie să fie private, metodele, publice.
Diag. de stări o facem doar pentru clase!
Modularizarea – este o tehnică de design software ce presupune separarea funcţionalului unui program independent în module, fiecare modul conţinînd cele necesare pentru a executa funcţionalitatea de sinestătătoare a acestuia.
Modul – element de grupare a altor elemente şi face parte dintr-un sistem. Modulele sunt dezvoltate în aşa fel încît să minimizeze dependenţele între ele. Dezvoltatorii pot crea modulele separat fără a cunoaşte celelalte module ale sistemului.
Componentă –
Principiile lui Parnas:
1. Scopul descompunerii în module este reducerea costrurilor prin posibilitatea de a proiecte şi revizui modulele în mod independent;
2. Modularizarea constă în divizarea programului într-un nr. de subunităţi care pot fi compilate separat, dar care sunt cuplate (conectate) între ele
- Gradul de cuplaj între module trebuie să fie mic;
- Clasele care compun un modul trebuie să aibă legături strînse între ele;
3. Încapsularea şi modularizarea reprezintă procese similare, dar care se desfăşoară la nivele diferite de abstractizare.
Low coupling (legătura slabă) – concept prin care clasele de pe diferite nievele trebuie să interacţioneze marginal. Schimbarea conţinutului unei clase nu trebuie să afecteze o altă clasă din acelaşi modul.
High conesion – presupune că o clasă trebuie să fie orientată spre realizarea unui singur lucru, şi nu mai multe odată.
Facade – este un obiect ce oferă o interfaţă simplificată pentru o bucată mare de cod, cum ar fi o librărie de clase.
Dezavantajele POO:
1. Documentarea este un proces mai dificil,
2. In structuri cu multe nivele de ierarhizare, uneori este foarte greu de urmarit, de la care clasa vine o anumita proprietate.
3. Utilizarea mai putin eficienta a memoriei:
- Referinta obiect + referinta tip
- Deseori unele obiecte au definite in cod metode pe care nu le ut.
Moştenirea este o proprietate a claselor ce permite transmiterea parametrilor de la o clasă la alta.
Signatura – numele funcţiei şi tipul parametrilor;
Una dintre problemele ce necesită atenţie, este găsirea nivelului corect de abstractizare la etapa iniţială de dezvoltare a soft-urilor. Una dintre greşelile tipice este acordarea atenţiei sporite asupra detaliilor de implementare (tehnologice) şi nu asupra structurii organizaţionale care ar pune accentul pe separarea responsabilităţilor.
Tema: Clase şi obiecte
Clasa – tip de date
Obiect – variabilă, instanţă a clasei;
Clase şi obiecte
Clasa, intr-un anumit limbaj de programare, reprezinta definirea unui tip de obiecte abstracte sau concrete, adica descrierea proprietatilor, a datelor si a metodelor, a prelucrarilor, posibile asupra datelor. Clasa este, de fapt, o notiune abstracta, care defineste un anumit tip de obiecte, sau, altfel spus, o clasa reprezinta multimea posibila a mai multor obiecte de acelasi tip.
Obiect este o instanta a unei clase, care utilizeaza atributele si implimenteaza metodele acesteia.
Crearea unui obiect presupune specificarea clasei din care face parte, astfel identificandu-se proprietatile obiectului si modul in care acestea pot fi folosite si prelucrate.
Parafrazarea principiilor lui Parnas:
- Declararea clasei trebuie să asigure clientul doar cu informaţia necesară pentru utilizarea eficientă a ei;
- Metodele trebuie să aibă acces doar la informaţia necesară pentru îndeplinirea responsabilităţilor lor;
- One must provide the client with all the information needed to use the module correctful, and nothing more.
- One must provide the implementer with all the information needed to complete the module, and nothing more.
Încapsularea este proprietatea obiectelor de a-şi ascunde o parte din atribute şi metode. Din exteriorul obiectului sunt accesibile/vizibile doar atributele şi metodele publice. Obiectul se comportă ca şi cînd ar avea 2 învelişuri, unul transparet, care permite accesul la datele obiectului, şi unul opac, care cuprinde datele private.
- Oferă independenţa implementării de interfaţă;
- Previne coruperea datelor interne;
- Permite mai multor echipe un lucru independent asupra modulelor;
- Măreşte siguranţa şi fiabilitatea programelor, prin eliminarea posibilităţii modificării accidentale a valorilor acestora.
Ierarhizarea – ordonarea/gruparea abstracţiilor obţinute..
- Ierarhii de clasă, moştenirea – moştenirea implicită o ierarhie de tip generalizare sau specializare; Între clase există relaţia „is a”.
- Ierarhii de obiecte, agregarea – relaia între 2 obiecte în care unul dintre obiecte aparţine celuilalt obiect; Există relaţie „has a”.
Ierarhizarea
Adesea un grup de abstractiuni formeaza o ierarhie, iar prin identificarea acestor ierarhii, putem simplifica substantial intelegerea problemei.
Ierarhizarea reprezinta o ordonare a abstractiunilor.
Cele mai importante ierarhii in paradigma obiectuala sunt:
Ierarhia de clase (relatie de tip "is a")
Ierarhia de obiecte (relatie de tip "part of")
Mostenirea (ierarhia de clase)
Mostenirea defineste o relatie intre clase in care o clasa impartaseste structura si comportarea definita in una sau mai multe clase (dupa caz vorbim de mostenire simpla sau multipla). Asa cum aminteam mai sus, relatia de mostenire este cea care face diferenta intre programarea orientata pe obiecte si cea bazata pe obiecte.
Semantic, mostenirea indica o relatie de tip "is a" ("este un/o"). De exemplu un urs "este un" mamifer si deci intre clasa ursilor si cea a mamiferelor exista o relatie de mostenire. Si in cazul programarii acesta este cel mai bun test pentru a detecta o relatie de mostenire intre doua clase A si B: A mosteneste pe B daca si numai daca putem spune ca "A este un fel de B". Daca A "nu este un" B atunci A nu ar trebui sa mosteneasca pe B.
Prin urmare, mostenirea implica o ierarhie de tip generalizare/specializare, in care clasa derivata specializeaza structura si comportamentul mai general al clasei din care a fost derivata.
Agregarea (ierarhia de obiecte)
Agregarea este relatia intre doua obiecte in care unul dintre obiecte apartine celuilalt obiect. Agregarea reda apartenta unui obiect la un alt obiect. Semantic, agregarea indica o relatie de tip "part of" ("parte din"). De exemplu intre o roata si un automobil exista o astfel de relatie, intrucat putem spune ca "o roata este o parte din automobil".
Membrii statici ai claselor
Varibilele statice sunt variabilele cărora li se alocă o singură zonă de memorie ce este utilizată pe tot parcursul programului, comparativ cu cele nestatice, cărora la fiecare apel, li se alocă o zonă nouă de memorie, ce este necesar apoi a fi dealocată.
static – artributul este static;
metode statice – doar atribute statice!
Membri statici.
Membrii statici exista in exemplare unice pentru fiecare clasa, find accesati in comun de toate instantele clasei repective.
Se recomanda ca referire unui membru static sa se faca prin intermediul numelui clasei si nu prin intermediul numelui obiect.
Declararea unui membru static presupune precedarea acestuia de cuvantul cheie static:
static tip_membru nume_membru_static;
iar referirea unui membru static se face astfel:
nume_clasa::nume_membru_static;
unde, nume_membru_static poate fi o data sau o functie membru static.
Membri static pot fii referiti fara a instantia clasa, ei nedepinzind de obiecte.
Destructori – metodă utilizată pentru dealocarea memoriei şi realizarea diferitor operaţii specifice eliminării obeictului;
Obiectul este distrus sau implicit sau cînd stopăm aplicaţia.
Parametrul trimis unei funcţii este o copie a obiectului!
X xobj(100)
G(xobj);
Return 0;
Destructoru se apeleaza de 2 ori!!!
În C++, parametrii transmişi ca valoare în funcţii şi metode crează copii ale acestor parametri şi aceste copii vor supuse tuturor operaţiunilor standarde pentru obiecte, inclusiv destructori.
În cazul creării obiectelor complexe (care au atribute de tip clasă) , ordinea constructorilor va fi următoarea:
- la început se aplelează constructorul atributelor, iar apoi constructorul clasei principale;
Pentru aceleaşi tipuri de obiecte, ordinea apelării destructorilor va fi inversă:
- La început se apelează destructorul clasei de bază, apoi destructorul atributului;
Organizarea claselor:
- După funcţionalitate:
o Uşurinţă în utilizare şi căutare;
o Evitarea conflictelor de nume;
o Constrolul accesului.
- Java: package;
- C++/C#: namespace;
- Librării: JAR(JVM), DLL(WINDOWS)
Modele de relaţii:
- Ierarhie conceptuală, ţine de domeniu, cum interacţ. În viaţa reală;
- Ierarhie de implementare, cum se impl. Concret în aplicaţie;
Ut. obiectelor poate fi de 3 tipuri:
- Is a, moştenire
- Has a, agregare/compoziţie
- Uses a, dependenţă.
Dependenţa între clase apare atunci cînd o clasă foloseşte obiecte ale altei clase în metodele sale (declară obiecte în corpul metodei sau primeşte obiecte ca parametri).
Moştenirea în C++
Specificatorii de acces definește drepturile de acces pentru atribute sau metode pe care-l urmează până la definirea unui alt specificator de acces sau până la sfârșitul unei clase. Cele trei tipuri de specificatori de acces sunt "private", "public", "protected".
private:
Membrii declarati ca "private", pot fi accesate numai în cadrul aceleiași clase, și nu din afara clasei.
Public:
Membrii declarat ca "public" sunt accesibile în cadrul clasei, cât și din afara ei.
protected:
Membrii declarat ca "protected" nu pot fi accesate din afara clasei, dar pot fi accesate de la o clasa mostenita. Aceasta este utilizată atunci când este aplicată mostenirea membrilor unei clase.
Moştenire Accesul în
Clasa de bază Clasa derivată
Public Public
Protected
Private Public
Protected
Private
Protected Public
Protected
Private Protected
Protected
Private
private Public
Protected
Private Private
Private
Private
Accesibilitatea membrilor in Java
In java sunt utilizate aceeasi specificatori ca si in C++ insa apare inca un specificator - “package-private(no modifier)”.
package-private(no modifier) – daca un atribut utilizeaza acest specificator atunci el este public pentru tot pachetul insa private pentru accesarea innafara pachetului.
Alpha Beta AlphaSub Gamma
Public Y Y Y Y
Protected Y Y Y N
Nu are Y Y N N
private Y N N N
Funcţia virtuală este funcţia care implică:
1 – redefinirea comportamentului în clasa derivată de o funcţie cu aceeaşi signatură;
2 – rezoluţia dinamică a comportamentului în dependenţă de obiect şi nu de tipul referinţei spre acest obiect;
3 – generarea unui tabel al funcţiilor virtuale, care păstrează pointeri spre funcţiile fiecărui obiect derivat:
- Fiecare clasă are propriul V-table;
- „Legare” tîrzie implică costuri de performanţă
F. virtuale sunt acele funcţii care sunt selectate în mod dinamic în timpul execuţiei aplicaţiei.
Parametrii statici ai funcţiilor nu permit folosirea virtualităţii claselor derivate deoarece aceştia fac o copii a obiectului transmis, pe care o tipizează (cast), conform tipului declarat în metodă.
Parametrii transmişi ca pointer sau referinţă folosesc obirctul primit şi nu îi schimbă tipul după cel declarat în metodă, respectiv, pentru acest obiect pot fi foloste fucţiile virtuale.
Şabloane de proiectare. Şablonul Strategy
Moştenirea multiplă - o clasă derivată are mai multe clase părinte
Mostenirea multipla este mecanismul prin care o clasă preia structura (datele membru) şi comportamentul (metodele) a doua sau mai multe clase la care adaugă elemente specifice.
Moştenire multiplă - clasa derivată preia caracteristicile şi metodele de la mai multe clase de bază.
Mostenirea multipla este prezenta in limbajul C++ si nu este implementata in C# sau Java (cu toate ca exista metode de utilizare a interfetelor pentru a realiza ceva de genul mostenirii multiple).
Polimorfism
Polimorfism – este o proprietate a OO prin care o metodă poate avea comportament diferit.
2 tipuri: universal şi adhoc;
Universal
- Incluziune
- Parametric
Ad-hoc
- Overloading
- Coercion(casting)
Polimorfism Cod sursă Parametri Relaţii argumente parametri
Overloading Diferit Diferiţi(ca tip sau nr) -
Coercion Acelaşi Aceeaşi Relaţia de convertabilitate dintre tipul parametrului şi argumentului
Inclusion Diferit Aceeaşi Relaţia de incluziune dintre tipul parametrului implicit şi argumentului metodei(adică tipul obiectului este un subtip al tipului referinţei).
Parametric Acelaşi Diferiţi(ca tip) -
Polimorfismul parametric presupune că diferenţa între funcţii se realizează prin lista de parametri şi/sau valoarea returnată, funcţiile având acelaşi nume. El se referă la posibilitatea utilizării unei singure funcţii (cod, nume, funcţionalitate) asupra unui set de tipuri, dacă un argument al semnăturii sale determină tipul corespunzător fiecărui apel al funcţiei.
Polimorfismul incluziune presupune manipularea obiectelor de un anumit tip în situaţii în care se cer tipuri diferite de tipul obiectelor. Astfel obiectele de tip ClasaDerivata pot fi utilizate în orice situaţie care necesită prezenţa unor obiecte de tipul ClasaDeBaza, unde ClasaDeBaza este o superclasă a clasei ClasaDerivata. Polimorfismul incluziune permite unei funcţii să opereze asupra unui set de tipuri determinate de relaţii de subtip (ierarhii de clase). Implementarea unei asemenea forme de polimorfism permite folosirea unor tehnici care să trateze un obiect ca instanţă a mai multor clase în acelaşi timp (între care există relaţii de superclasa-subclasă). În acest fel organizarea şi prelucrarea colecţiilor de obiecte eterogene se face într-o manieră flexibilă şi elegantă.
Polimorfismul ad-hoc la rândul său se împarte în polimorfism coerciziune şi polimorfism supraîncărcare.
Polimorfismul coerciziune este caracteristic limbajelor de programare care dispun de facilităţi de conversie internă între tipuri.
Polimorfismul supraîncărcare se obţine prin supraîncărcarea funcţiilor şi mascarea lor în cadrul unei ierarhii de clase. Atfel, operaţiile polimorfice sunt operaţii cu acelaşi nume dar cu implementări diferite. De exemplu, de-a lungul unei ierarhii de clase, o operaţie definită într-o superclasă poate fi redefinită într-o subclasă. Astfel ea este polimorfică, decizia de selecţie a funcţiei active luându-se în funcţie de parametri de apel.
Specifice limbajului C++ sunt polimorfismul ad-hoc şi polimorfismul de incluziune, acesta din urmă realizându-se prin intermediul funcţiilor virtuale şi a legării dinamice.
Avantajele sistemelor polimorfice sunt partajabilitatea comportării, posibilitatea de definire a operaţiilor abstracte asociate tipurilor, flexibilitate.
Principii de proiectare (SOLID)
SOLID este un acronim care reprezintă un set din 5 principii care , în cazul în care sunt respectate, permit să dezvoltăm o arhitectură flexibilă şi uşor de menţinut pentru o perioadă mai lungă de timp. Principiile sunt următoarele:
SRP – Single Responsibility Principle , o clasă trebuie să aibă doar un motiv(domeniu), pentru care trebuie să se modifice. Dacă o clasă are mai mult decît o responabilitate, atunci, acestea devin cuplate. Modificările în una dintre responsabilităţi pot să afecteze capacitatea clasei de a păstra corectitudinea celorlalte. Acest tip de cuplare duce la o arhitectură fragilă care poate genera erori neaşteptate.
OCD – Open Closed Principled, o clasă trebuie să fie extensibilă fără a o modifică. Entităţile software (module, clase) trebuie să fie deschise pentru extindere, dar închise pentru modificare.
Trebuie să proiectăm modulele astfel încît ele să nu se modifice. Cînd apar schimbări de cerinţe, extinderea comportamentului ar trebui realizată prin adăugarea de nou cod, ci nu prin modificarea celui Acest principiu este foarte important cînd dezvoltăm şi menţinem biblioteci şi aplicaţii care se planifică să creeeească în timp. Este mai bine să creăm mai multe interfeţe separate, combinate într-un API (ăi pi ai), decît să unificăm toate metodele publice într-o singură clasă.
Exemplu din caiet:
În acest exemplu, principiul AI ĂS PI (ISP) nu este respectat deoarece clientul (clasa Manager) foloseşte interfaţa Iworker care conţine mai multe metode decît îi sunt necesare. Pentru a rezolva această problemă, trebuie să plasăm metoda eat într-o altă interfaţă.s
DIP – Dependency Inversion Principle, inversării dependenţei, clasele trebuie să depindă de abstracţii şi nu de implementări.
Metodele de nivel înalt nu trebuie să depindă de cele de nivel jos şi ambele trebuie să depindă de abstracţii.
Abstracţiile nu trebuie să depinde de detalii, ci invers, detaliile de abstracţii. Trebuie să folosim multe interfeţe şi abstracţii.
Principiul DIP spune că dacă o clasă depinde de alte clase, ea ar trebui să utilizeze interfeţe în loc de tipuri (clase concrete), adică ar trebui să izolăm clasa prin abstracţii de care ea depinde. Dacă detaliile în spatele ebstracţiilor se modifică, clasa noastră rămîne neschimbată. Aceasta ne permite să avem o legătura mai slabă (low coupling) între clase.
Exemplul (clasa Worker) violează DIP deoarece clasa Manger (modul de nivel înalt) depinde direct de clasa Worker (modul de nivel jos), şi nu există nici o abstracţie între aceste 2 clase care ar permite clasei manager să fie independentă de modulul de nivel jos. Respectiv, apariţia clasei SuperWorker ne impune să facem modificări în clasa manager pentru ca aceasta să fie susţinută.
Nivel jos – ceea ce realizează funcţionalul;
Nivel înalt – ceea ce ar utiliza nivelul jos;
Principii de proiectare GRASP
Principiile GRASP sunt un set de principii implementate sau aplicate în OOP, care ne permit o dezvoltare mai facilă a soft-ului.
Acronimul GRASP vine de la General Responsibility Assignment Software Patterns. Aceste principii ţin de modul în care sînt distribuite responsabilităţile între clase. Există 2 tipuri de responsabilităţi:
1. De realizare;
2. De cunoaştere;
Resp. de realizare ţin de comportamentul (metodele) claselor şi pot fi stabilite la etapa de modelare (diagrame de interacţiuni ne sugerează aceasta prin mesajele transmise).
Resp. de cunoaştere ţin de datele de care clasa trebuie să le manipuleze.
Există 9 principii:
1. Creator
2. Information Expert
3. Low Coupling
4. Controller
5. High Cohesion
6. Polymorphism
7. Pure Fabrication (invenţie pură)
8. Indirection
9. Protected Variations
Creator
Problemă: Cine ar fi responsabil de crearea instanţei noi unei clase?
Soluţia: Atribuiţi clasei B responsabilitatea de a crea instanţa clasei A dacă unu lasu mai multe puncte de mai jos pot fi aplicate. Dacă mai multe de o opţiune poate fi aplicată, preferaţi clasa B care conţine atributul de tip A.
- B conţine un atribut de tip A.
- B înregistrează A. (el populează datele lui A)
- B ut. foarte mult A; (are multe metode în care are parametri de tip A)
- B are datele de iniţializare ale lui A şi le va transmite obiectului de tip A atunci cînd acesta este creat.
Information Expert
Problemă: Care este principiul general de atribuire a responsabilităţilor la obiect?
Soluţie: Atribuiţi responsabilitatea la expert clasa care are informaţia necesară pentru a îndeplini responsabilitatea.
Acest principiu este unul din cele mai des întîlnite şi este un factor cheie pentru asigurarea cuplării slabe şi coeziunii de nivel înalt.
Low Coupling
Problemă: Cum să asigurăm dependenţele de nivel jos (slabă), impact slab la modificare şi nivel ridicat de reutilizare?
Soluţia: Atribuiţi responsabilitatea astfel încît legături să fie cît mai puţine.
Acest principiu presupune evaluarea tuturor alternativelor şi alegerea celei mai posibile legături. Cuplarea se referă la dependenţele dintre clase, sub-sisteme, sisteme etc. Poate fi împărţită în 2 categorii: slabă (bine)/înaltă (rău).
Cuplarea de nivel înalt poate duce la:
1. Mai multă dificultate în înţelegerea codului.
2. Propagarea excesivă a modificărilor.
3. Mai multe obstacolr în reutilizarea codului.
Controller
Problemă: Care este primul obiect din spatele nivelului UI care primeşte şi coordonează lucrul sistemului?
Soluţia: Atribuiţi această responsabilitate unuia dintre tipurile date de clase:
- Controller Facade – reprezintă sistemul în întregime şi oferă un punct de intrare în sistem. (de văzut şablonul FACADE din Design Patterns).
- Controller UseCase/Sesiune – reprezintă o clasă ce prelucrează mesajul de intrare într-un scenariu.
Un controller încearcă să coordoneze lucrul fără a realiza prea multe. Cuvîntul cheie pentru controller este delgare. Controller-ul primeşte cererea şi hotărăşte ce cui să o transmită mai departe.
Controller-ul este un element care poate fi folosit în implementarea şablonului FACADE. Acest şablon e un punct de intrare în sistem, separînd clientul de detaliile de implementare prin oferirea unei interfeţe publice (care are un timp de viaţă destul de lung),
High Cohesion
Problemă: cum să păstrăm obiectele/clasele focusate, uşor de înţeles şi coordonat şi în acelaşi timp să susţinem principiul low coupling?
Soluţia: atribuiţi responsabilitatea astfel încît legăturile interne să rămîna puternice. Coeziunea se referă la legăturile funcţionale dintre elemente care este o metrică (ex. Timp de încărcare) a focusării responsabilităţilor unui element.
O coeziune mai slabă, în majoritatea cazurilor duce la:
1. Un element va fi mai greu de înţeles, menţinut şi reutilizat;
2. Un element este mai probabil să fie afectat de modificări;
Recomandarea în acest caz este de a găsi locul potrivit în modulul necesar şi/sau utilizarea mai frecventă a delegării.
Polimorfismul
Problema: cum coordonăm soluţiile alternative ce se bazează pe tipul obiectului. Cum să creăm componente software ce pot fi schimbate în timp real?
Soluţia: Cînd alternativele sau comportamentul variază după tipul clasei, atribuim responabilităţile utilizînd operaţii polimorfice. Aceste operaţii vor fi distribuite pe clase diferite, însă vor avea semnături identice.
Pure Fabrication
Problemă: care obiect ar trebui să aibă responsabilitatea atunci cînd nu dorim să violăm High Cohesion şi Low Coupling. Însă, soluţiile oferite de expert nu sunt potrivite.
Soluţia: Atribuiţi un set de responsabilităţi strîns legate unei clase artificiale care nu reprezintă un concept din domeniu, însă va susţine reutilizarea, cuplarea slabă şi coeziunea înaltă.
Exemple de pure fabrication pot fi toate şabloanele de proiectare din lista GOF.
Indirection
Problema: cui trebuie de atribuit resp. pentru a evita cuplarea directă dintre 2 sau mai multe clase? Cum să decuplăm obiectele a.î. să susţinem cuplarea slabă şi să păstrăm reutilizarea la un nivel înalt.
Soluţia: atribuiţi resp. unui obiect intermediar care va media interacţiunile dintre obiectele ce nu sunt cuplate direct .
Foarte des, acest intermediar, este şi el o itenţie pură (pure fabrication). Exemple de indirection sunt şabloanele Adapter, Bridge, Facade, Observer, Mediator.
Protected Variations
Problemă: cum să proiectăm elementele (clase/subsisteme/sisteme) astfel încît variaţiile lor sau instabilitatea cerinţelor faţă de ele să nu aibă un efect nedorit asupra altor elemente.
Soluţia:Identificaţi punctele de instabilitate sau variaţie preconizată. Atribuiţi resp. astfel încît să creaţi o interfaţă stabilă în jurul lor.
Determinarea şi analiza cerinţelor
O cerinţă este o afirmaţie, ceea ce trebuie să facă sistemul, sau un set de caracteristici pe care trebuie să le aibă sistemul.
Este important de a înţelege că cerinţele se pot schimba pe parcursul dezvoltării proiectului.
Există 2 tipuri de cerinţe: funcţionale/non-funcţionale.
C. funcţionale descriu procesele pe care trebuie să le realizeze sistemul şi informaţia pe care acesta trebuie să o conţină. Restul cerinţelor, ce nu intră în descrierea de mai sus, sunt non-funcţionale (ex. Cerinţe operaţionale, de performanţă, de securitate etc).
Surse de cerinţe
1. Clienţii
2. Utilizatori
3. Administratori, personal de mentenaţă
4. Parteneri
5. Experţii în domeniu
6. Analişti ai industriei
7. Informaţii despre concurenţi
Tehnici de colectare a cerinţelor
Abilităţile necesare pentru colectarea cerinţelor:
- Impertinenţa (derzosti)
- Imparţialitatea (a nu ţine partea cuiva)
- Capacitatea de a relaxa constrîngerile (scoaterea constr.)
- Atenţie la detalii
- Schimbarea punctului de vedere
Tehnici:
- Interviurile
- Chestionarele
- Sesiuni JAD
- Prototyping
Prototyping
Prototipizarea este o tehnică de colectare a cerinţelor în care se construieşte o versiune primară a sistemului ce va fi un punct de start pentru colectarea cerinţelor ulterioare.
Tool-uri: Axure
Condiţiile de utilizare a prototipizării:
1) Procesul dat trebuie să fie repetitiv;
2) Este creată o versiune rudimentară a sistemului;
3) Scopul este de a crea specificaţii concrete pentru sistemul final;
4) Există posibilitatea convertirii rapide din cerinţe în sistem funcţional;
5) După ce utilizatorul vede cerinţele implementate în prototip, de regulă, el cere alte modificări.
Cînd este prototip. cea mai utilă:
1. Atunci cînd cerinţele clienţilor nu sînt clare;
2. Sunt implicate puţine persoane în procesul de determinare a cerinţelor;
3. Cînd design-ul grafic este complex şi necesită o formă concretă.
4. Cînd există o istorie a comunicării problematice între clienţi şi dezvoltatori.
5. Există instrumente pentru prototipizare.
Puncte negative ale prototipizării:
1. Tendinţa de a evita documentaţia formalizată.
2. Dificultatea de a adapta prototipul la un grup de utilizatori mai general.
3. Partajarea datelor cu alte sisteme este deseori ignorată.
4. Termenii ciclului de dezv. A soft-ului foarte des nu sunt respectaţi.
Alte tehnici:
- Interviu unul la unul
- Interviu în grup
- Brainstorming
- Interface Analysis (analiza interfeţelor) – obţ. Setul de funcţionalităţi;
- Reverse Engeneering – avem cod sursă, obţinem din el cerinţe/diagrame/structură;
- Study analogous systems (studierea sistemelor analogice) – concurenţii;
Analiza cerinţelor
1. Recunoaşterea problemei (identificarea) – ident. probl. şi vedem dacă este un risc etc.
2. Evaluare şi sinteză – focusarea la ce trebuie de făcut, ci nu cum trebuie;
3. Modelare
4. Specificare
5. Review
Întrebari de management
- Cît de mult efort punem în analiză?
- Ce face analiza?
- De ce este atît de dificil?
- Cine plăteşte?
Studii de fezabilitate (arată dacă proiectul poate/are sens a fi făcut):
- Fez. Economică
- Fez. Tehnică (resurse tehnice)
- Fez. Legală
- Alternative
Specificaţiile sistemului
- Introducere
- Descrierea funcţionalului
- Descrierea sub-sistemelor
- Modelare sistemului şi simularea rezultatelor
- Produse
- Anexe
Validarea cerinţelor
- Este cerinţa corectă sau nu?
- Este cerinţa consistentă?
- Este ea completă?
…
Modelare
CÎnd modelăm sistemul, luăm în consideraţie:
1. Modelul de date care ne arată relaţiile între obiectele sistemului;
2. Modeul funcţional descrie funcţiile care transformă obiectele de sistem şi modelul de comportament, descrie modul în care sistemul răspunde la evenimentele din afară;
3. Modelul de comportament descrie interfeţele de acces la sistem (API-uri etc.);
Principiile de descriere a specificaţiilor
1. Separarea funcţionalităţilor de implementare(atunci cînd specificăm funcţ., nu trebuie să spunem cum le vor realiza);
2. Este necesar a folosi un limbaj de specificare orientat pe procese (ex. UML);
3. Specificaţiile trebuie să conţină componentele software ale sistemului;
4. Specificaţiile trebuie să fie operaţionale (să răspundă la întrebarea CUM TREBUIE ACEASTA SĂ LUCREZE?/CUM TREBUIE REALIZAT?);
5. Trebuie să fie simplu de adăugat specificaţii noi şi în acelaşi timp, lipsa tuturor detaliilor nu trebuie să împiedice înţelegerea sistemului;
6. Specificaţiile trebuie să fie localizate şi cuplate slab;
Review-ul specificaţiilor
1. Revizuirea este realizată de client şi developer;
2. Odată aprobată, specificaţia devine un contract pentru dezvoltarea soft-ului;
3. Specificaţia este dificil de testat în mod logic;
4. Estimarea impactului schimbării de specificaţie este foarte greu de realizat;
Revizuirea cerinţelor
1. Revizuirea obiectivelor şi scopurilor;
2. Comparăm cerinţele ca să corespundă obiectivelor şi scopurilor;
3. Trebuie luat în consideraţie mediul de operare al sistemului;
4. Estimăm şi documentăm toate riscurile în operarea sistemului dezvoltat (atît în regim de producţie cît şi de testare şi dezvoltare);
5. Discutarea procedurilor de testare a cerniţelor;
Erori tipice în analiza cerinţelor
1. Clienţii nu chiar ştiu ceea ce vor;
2. Cerinţele se modifică pe parcursul proiectului;
3. Clienţii cer termeni ne-rezonabili;
4. Există probleme de comunicare între clienţi, ingineri şi manageri de proiect;
5. Echipa de dezvoltare nu înţelege politica organizaţiei clientului;
Etapa de proiectare. Arhitecturi
Definiţie: o arhitectură software cuprinde setul de decizii importante şi deciziile ce ţin de organizarea unui sistem software, incluzînd alegerea elementelor structurale şi a interfeţelor lor; Comportamentul specificat în colaborarea dintre aceste elemente; compoziţia acestor elemente structurale şi de comportament în sub-sisteme mai mari; un stil arhitectural care conduce sau ghidează această organizaţie.
Arhitectura se bazează pe cerinţele deja analizate.
Ca şi orice structură complexă, soft-ul trebuie să aibă un fundament solid. Instrumentele şi platformele moderne ne permit să simplificăm procesul de creare a aplicaţiilor, însă, nu înlocuiesc necesitatea de a proiecta aplicaţia, bazîndu-ne pe cerinţe şi scenarii specifice. Riscul proiectării slabe duce la soft instabil , greu de menţinut şi de dezvoltat.
Delegare
- principiu cheie al OOP, permite să grupăm un anumit funcţional într-un anumit element.
- Transmiterea responsabilităţilor către alte obiecte;
Chain of responsability
O aplicaţie OOP este structurată ca o comunitate de agenţi care interacţionează, numiţi obiecte. Fiecare obiect are un rol şi oferă un serviciu sau realizează o acţiune care este utilizată de alţi membri ai comunităţii.
O acţiune este iniţiată în aplicaţiile OOP prin transmiterea unui mesaj către un agent, responsabil de acţiune. Mesajul care reprezintă cererea la acţiune este acompaniat de altă informaţie adăugătoare, argumente, parametri, necesari pentru a realiza cererea.
Receptorul este obiectul care primeşte mesajul. Dacă receptorul acceptă mesajul, el acceptă responsabilitatea de a realiza această acţiune. Ca răspuns la mesaj, receptorul execută o metodă pentru a satisface cererea.
Tema: Paradigma POO. Abstracţii
Abstracţie – metodă/proces de eliminare a caracteristicilor numeroase unui obiect pentru a-l reduce la un set de caracteristici generale. În OOP, este unul din cele 3 principii centrale, pe lîngă incapsulare şi moştenire. În procesul de abstractizare, programatorul ascunde datele importante despre obiect pentru a reduce complexitatea şi a mări eficienţa.
Programarea orientata pe obiecte este o metoda de implementare in care programele sunt organizate ca ansamble de obiecte ce coopereaza intre ele, fiecare obiect reprezentand instanta unei clase; fiecare clasa apartine unei ierarhii de clase in cadrul careia clasele sunt legate prin relatii de mostenire.
Aceasta definitie cuprinde trei parti importante, si anume:
• obiectele si nu algoritmii sunt blocurile logice fundamentale;
• fiecare obiect este o instanta a unei clase. Clasa este o descriere a unei multimi de obiecte caracterizate prin structura si comportament similare.
• clasele sunt legate intre ele prin relatii de mostenire.
Principii:
1. Totul este obiect;
2. Obiectele interacţionează prin transmiterea şi primirea mesajelor;
3. Fiecare obiect îşi are memoria proprie;
4. Fiecare obiect aparţine unui grup de obiecte – clasă;
5. Clasa defineşte comportamentul comun tuturor obiectelor – exemplalelor sale;
6. Clasele se organizează într-o structură arborescentă cu o rădăcină comună, asigurîndu-se „Transferul” de comportament de la clasele superioare claselor inferioare din ierarhia de moştenire.
7. Obiectele trebuie să fie private, metodele, publice.
Diag. de stări o facem doar pentru clase!
Modularizarea – este o tehnică de design software ce presupune separarea funcţionalului unui program independent în module, fiecare modul conţinînd cele necesare pentru a executa funcţionalitatea de sinestătătoare a acestuia.
Modul – element de grupare a altor elemente şi face parte dintr-un sistem. Modulele sunt dezvoltate în aşa fel încît să minimizeze dependenţele între ele. Dezvoltatorii pot crea modulele separat fără a cunoaşte celelalte module ale sistemului.
Componentă –
Principiile lui Parnas:
1. Scopul descompunerii în module este reducerea costrurilor prin posibilitatea de a proiecte şi revizui modulele în mod independent;
2. Modularizarea constă în divizarea programului într-un nr. de subunităţi care pot fi compilate separat, dar care sunt cuplate (conectate) între ele
- Gradul de cuplaj între module trebuie să fie mic;
- Clasele care compun un modul trebuie să aibă legături strînse între ele;
3. Încapsularea şi modularizarea reprezintă procese similare, dar care se desfăşoară la nivele diferite de abstractizare.
Low coupling (legătura slabă) – concept prin care clasele de pe diferite nievele trebuie să interacţioneze marginal. Schimbarea conţinutului unei clase nu trebuie să afecteze o altă clasă din acelaşi modul.
High conesion – presupune că o clasă trebuie să fie orientată spre realizarea unui singur lucru, şi nu mai multe odată.
Facade – este un obiect ce oferă o interfaţă simplificată pentru o bucată mare de cod, cum ar fi o librărie de clase.
Dezavantajele POO:
1. Documentarea este un proces mai dificil,
2. In structuri cu multe nivele de ierarhizare, uneori este foarte greu de urmarit, de la care clasa vine o anumita proprietate.
3. Utilizarea mai putin eficienta a memoriei:
- Referinta obiect + referinta tip
- Deseori unele obiecte au definite in cod metode pe care nu le ut.
Moştenirea este o proprietate a claselor ce permite transmiterea parametrilor de la o clasă la alta.
Signatura – numele funcţiei şi tipul parametrilor;
Una dintre problemele ce necesită atenţie, este găsirea nivelului corect de abstractizare la etapa iniţială de dezvoltare a soft-urilor. Una dintre greşelile tipice este acordarea atenţiei sporite asupra detaliilor de implementare (tehnologice) şi nu asupra structurii organizaţionale care ar pune accentul pe separarea responsabilităţilor.
Tema: Clase şi obiecte
Clasa – tip de date
Obiect – variabilă, instanţă a clasei;
Clase şi obiecte
Clasa, intr-un anumit limbaj de programare, reprezinta definirea unui tip de obiecte abstracte sau concrete, adica descrierea proprietatilor, a datelor si a metodelor, a prelucrarilor, posibile asupra datelor. Clasa este, de fapt, o notiune abstracta, care defineste un anumit tip de obiecte, sau, altfel spus, o clasa reprezinta multimea posibila a mai multor obiecte de acelasi tip.
Obiect este o instanta a unei clase, care utilizeaza atributele si implimenteaza metodele acesteia.
Crearea unui obiect presupune specificarea clasei din care face parte, astfel identificandu-se proprietatile obiectului si modul in care acestea pot fi folosite si prelucrate.
Parafrazarea principiilor lui Parnas:
- Declararea clasei trebuie să asigure clientul doar cu informaţia necesară pentru utilizarea eficientă a ei;
- Metodele trebuie să aibă acces doar la informaţia necesară pentru îndeplinirea responsabilităţilor lor;
- One must provide the client with all the information needed to use the module correctful, and nothing more.
- One must provide the implementer with all the information needed to complete the module, and nothing more.
Încapsularea este proprietatea obiectelor de a-şi ascunde o parte din atribute şi metode. Din exteriorul obiectului sunt accesibile/vizibile doar atributele şi metodele publice. Obiectul se comportă ca şi cînd ar avea 2 învelişuri, unul transparet, care permite accesul la datele obiectului, şi unul opac, care cuprinde datele private.
- Oferă independenţa implementării de interfaţă;
- Previne coruperea datelor interne;
- Permite mai multor echipe un lucru independent asupra modulelor;
- Măreşte siguranţa şi fiabilitatea programelor, prin eliminarea posibilităţii modificării accidentale a valorilor acestora.
Ierarhizarea – ordonarea/gruparea abstracţiilor obţinute..
- Ierarhii de clasă, moştenirea – moştenirea implicită o ierarhie de tip generalizare sau specializare; Între clase există relaţia „is a”.
- Ierarhii de obiecte, agregarea – relaia între 2 obiecte în care unul dintre obiecte aparţine celuilalt obiect; Există relaţie „has a”.
Ierarhizarea
Adesea un grup de abstractiuni formeaza o ierarhie, iar prin identificarea acestor ierarhii, putem simplifica substantial intelegerea problemei.
Ierarhizarea reprezinta o ordonare a abstractiunilor.
Cele mai importante ierarhii in paradigma obiectuala sunt:
Ierarhia de clase (relatie de tip "is a")
Ierarhia de obiecte (relatie de tip "part of")
Mostenirea (ierarhia de clase)
Mostenirea defineste o relatie intre clase in care o clasa impartaseste structura si comportarea definita in una sau mai multe clase (dupa caz vorbim de mostenire simpla sau multipla). Asa cum aminteam mai sus, relatia de mostenire este cea care face diferenta intre programarea orientata pe obiecte si cea bazata pe obiecte.
Semantic, mostenirea indica o relatie de tip "is a" ("este un/o"). De exemplu un urs "este un" mamifer si deci intre clasa ursilor si cea a mamiferelor exista o relatie de mostenire. Si in cazul programarii acesta este cel mai bun test pentru a detecta o relatie de mostenire intre doua clase A si B: A mosteneste pe B daca si numai daca putem spune ca "A este un fel de B". Daca A "nu este un" B atunci A nu ar trebui sa mosteneasca pe B.
Prin urmare, mostenirea implica o ierarhie de tip generalizare/specializare, in care clasa derivata specializeaza structura si comportamentul mai general al clasei din care a fost derivata.
Agregarea (ierarhia de obiecte)
Agregarea este relatia intre doua obiecte in care unul dintre obiecte apartine celuilalt obiect. Agregarea reda apartenta unui obiect la un alt obiect. Semantic, agregarea indica o relatie de tip "part of" ("parte din"). De exemplu intre o roata si un automobil exista o astfel de relatie, intrucat putem spune ca "o roata este o parte din automobil".
Membrii statici ai claselor
Varibilele statice sunt variabilele cărora li se alocă o singură zonă de memorie ce este utilizată pe tot parcursul programului, comparativ cu cele nestatice, cărora la fiecare apel, li se alocă o zonă nouă de memorie, ce este necesar apoi a fi dealocată.
static – artributul este static;
metode statice – doar atribute statice!
Membri statici.
Membrii statici exista in exemplare unice pentru fiecare clasa, find accesati in comun de toate instantele clasei repective.
Se recomanda ca referire unui membru static sa se faca prin intermediul numelui clasei si nu prin intermediul numelui obiect.
Declararea unui membru static presupune precedarea acestuia de cuvantul cheie static:
static tip_membru nume_membru_static;
iar referirea unui membru static se face astfel:
nume_clasa::nume_membru_static;
unde, nume_membru_static poate fi o data sau o functie membru static.
Membri static pot fii referiti fara a instantia clasa, ei nedepinzind de obiecte.
Destructori – metodă utilizată pentru dealocarea memoriei şi realizarea diferitor operaţii specifice eliminării obeictului;
Obiectul este distrus sau implicit sau cînd stopăm aplicaţia.
Parametrul trimis unei funcţii este o copie a obiectului!
X xobj(100)
G(xobj);
Return 0;
Destructoru se apeleaza de 2 ori!!!
În C++, parametrii transmişi ca valoare în funcţii şi metode crează copii ale acestor parametri şi aceste copii vor supuse tuturor operaţiunilor standarde pentru obiecte, inclusiv destructori.
În cazul creării obiectelor complexe (care au atribute de tip clasă) , ordinea constructorilor va fi următoarea:
- la început se aplelează constructorul atributelor, iar apoi constructorul clasei principale;
Pentru aceleaşi tipuri de obiecte, ordinea apelării destructorilor va fi inversă:
- La început se apelează destructorul clasei de bază, apoi destructorul atributului;
Organizarea claselor:
- După funcţionalitate:
o Uşurinţă în utilizare şi căutare;
o Evitarea conflictelor de nume;
o Constrolul accesului.
- Java: package;
- C++/C#: namespace;
- Librării: JAR(JVM), DLL(WINDOWS)
Modele de relaţii:
- Ierarhie conceptuală, ţine de domeniu, cum interacţ. În viaţa reală;
- Ierarhie de implementare, cum se impl. Concret în aplicaţie;
Ut. obiectelor poate fi de 3 tipuri:
- Is a, moştenire
- Has a, agregare/compoziţie
- Uses a, dependenţă.
Dependenţa între clase apare atunci cînd o clasă foloseşte obiecte ale altei clase în metodele sale (declară obiecte în corpul metodei sau primeşte obiecte ca parametri).
Moştenirea în C++
Specificatorii de acces definește drepturile de acces pentru atribute sau metode pe care-l urmează până la definirea unui alt specificator de acces sau până la sfârșitul unei clase. Cele trei tipuri de specificatori de acces sunt "private", "public", "protected".
private:
Membrii declarati ca "private", pot fi accesate numai în cadrul aceleiași clase, și nu din afara clasei.
Public:
Membrii declarat ca "public" sunt accesibile în cadrul clasei, cât și din afara ei.
protected:
Membrii declarat ca "protected" nu pot fi accesate din afara clasei, dar pot fi accesate de la o clasa mostenita. Aceasta este utilizată atunci când este aplicată mostenirea membrilor unei clase.
Moştenire Accesul în
Clasa de bază Clasa derivată
Public Public
Protected
Private Public
Protected
Private
Protected Public
Protected
Private Protected
Protected
Private
private Public
Protected
Private Private
Private
Private
Accesibilitatea membrilor in Java
In java sunt utilizate aceeasi specificatori ca si in C++ insa apare inca un specificator - “package-private(no modifier)”.
package-private(no modifier) – daca un atribut utilizeaza acest specificator atunci el este public pentru tot pachetul insa private pentru accesarea innafara pachetului.
Alpha Beta AlphaSub Gamma
Public Y Y Y Y
Protected Y Y Y N
Nu are Y Y N N
private Y N N N
Funcţia virtuală este funcţia care implică:
1 – redefinirea comportamentului în clasa derivată de o funcţie cu aceeaşi signatură;
2 – rezoluţia dinamică a comportamentului în dependenţă de obiect şi nu de tipul referinţei spre acest obiect;
3 – generarea unui tabel al funcţiilor virtuale, care păstrează pointeri spre funcţiile fiecărui obiect derivat:
- Fiecare clasă are propriul V-table;
- „Legare” tîrzie implică costuri de performanţă
F. virtuale sunt acele funcţii care sunt selectate în mod dinamic în timpul execuţiei aplicaţiei.
Parametrii statici ai funcţiilor nu permit folosirea virtualităţii claselor derivate deoarece aceştia fac o copii a obiectului transmis, pe care o tipizează (cast), conform tipului declarat în metodă.
Parametrii transmişi ca pointer sau referinţă folosesc obirctul primit şi nu îi schimbă tipul după cel declarat în metodă, respectiv, pentru acest obiect pot fi foloste fucţiile virtuale.
Şabloane de proiectare. Şablonul Strategy
Moştenirea multiplă - o clasă derivată are mai multe clase părinte
Mostenirea multipla este mecanismul prin care o clasă preia structura (datele membru) şi comportamentul (metodele) a doua sau mai multe clase la care adaugă elemente specifice.
Moştenire multiplă - clasa derivată preia caracteristicile şi metodele de la mai multe clase de bază.
Mostenirea multipla este prezenta in limbajul C++ si nu este implementata in C# sau Java (cu toate ca exista metode de utilizare a interfetelor pentru a realiza ceva de genul mostenirii multiple).
Polimorfism
Polimorfism – este o proprietate a OO prin care o metodă poate avea comportament diferit.
2 tipuri: universal şi adhoc;
Universal
- Incluziune
- Parametric
Ad-hoc
- Overloading
- Coercion(casting)
Polimorfism Cod sursă Parametri Relaţii argumente parametri
Overloading Diferit Diferiţi(ca tip sau nr) -
Coercion Acelaşi Aceeaşi Relaţia de convertabilitate dintre tipul parametrului şi argumentului
Inclusion Diferit Aceeaşi Relaţia de incluziune dintre tipul parametrului implicit şi argumentului metodei(adică tipul obiectului este un subtip al tipului referinţei).
Parametric Acelaşi Diferiţi(ca tip) -
Polimorfismul parametric presupune că diferenţa între funcţii se realizează prin lista de parametri şi/sau valoarea returnată, funcţiile având acelaşi nume. El se referă la posibilitatea utilizării unei singure funcţii (cod, nume, funcţionalitate) asupra unui set de tipuri, dacă un argument al semnăturii sale determină tipul corespunzător fiecărui apel al funcţiei.
Polimorfismul incluziune presupune manipularea obiectelor de un anumit tip în situaţii în care se cer tipuri diferite de tipul obiectelor. Astfel obiectele de tip ClasaDerivata pot fi utilizate în orice situaţie care necesită prezenţa unor obiecte de tipul ClasaDeBaza, unde ClasaDeBaza este o superclasă a clasei ClasaDerivata. Polimorfismul incluziune permite unei funcţii să opereze asupra unui set de tipuri determinate de relaţii de subtip (ierarhii de clase). Implementarea unei asemenea forme de polimorfism permite folosirea unor tehnici care să trateze un obiect ca instanţă a mai multor clase în acelaşi timp (între care există relaţii de superclasa-subclasă). În acest fel organizarea şi prelucrarea colecţiilor de obiecte eterogene se face într-o manieră flexibilă şi elegantă.
Polimorfismul ad-hoc la rândul său se împarte în polimorfism coerciziune şi polimorfism supraîncărcare.
Polimorfismul coerciziune este caracteristic limbajelor de programare care dispun de facilităţi de conversie internă între tipuri.
Polimorfismul supraîncărcare se obţine prin supraîncărcarea funcţiilor şi mascarea lor în cadrul unei ierarhii de clase. Atfel, operaţiile polimorfice sunt operaţii cu acelaşi nume dar cu implementări diferite. De exemplu, de-a lungul unei ierarhii de clase, o operaţie definită într-o superclasă poate fi redefinită într-o subclasă. Astfel ea este polimorfică, decizia de selecţie a funcţiei active luându-se în funcţie de parametri de apel.
Specifice limbajului C++ sunt polimorfismul ad-hoc şi polimorfismul de incluziune, acesta din urmă realizându-se prin intermediul funcţiilor virtuale şi a legării dinamice.
Avantajele sistemelor polimorfice sunt partajabilitatea comportării, posibilitatea de definire a operaţiilor abstracte asociate tipurilor, flexibilitate.
Principii de proiectare (SOLID)
SOLID este un acronim care reprezintă un set din 5 principii care , în cazul în care sunt respectate, permit să dezvoltăm o arhitectură flexibilă şi uşor de menţinut pentru o perioadă mai lungă de timp. Principiile sunt următoarele:
SRP – Single Responsibility Principle , o clasă trebuie să aibă doar un motiv(domeniu), pentru care trebuie să se modifice. Dacă o clasă are mai mult decît o responabilitate, atunci, acestea devin cuplate. Modificările în una dintre responsabilităţi pot să afecteze capacitatea clasei de a păstra corectitudinea celorlalte. Acest tip de cuplare duce la o arhitectură fragilă care poate genera erori neaşteptate.
OCD – Open Closed Principled, o clasă trebuie să fie extensibilă fără a o modifică. Entităţile software (module, clase) trebuie să fie deschise pentru extindere, dar închise pentru modificare.
Trebuie să proiectăm modulele astfel încît ele să nu se modifice. Cînd apar schimbări de cerinţe, extinderea comportamentului ar trebui realizată prin adăugarea de nou cod, ci nu prin modificarea celui Acest principiu este foarte important cînd dezvoltăm şi menţinem biblioteci şi aplicaţii care se planifică să creeeească în timp. Este mai bine să creăm mai multe interfeţe separate, combinate într-un API (ăi pi ai), decît să unificăm toate metodele publice într-o singură clasă.
Exemplu din caiet:
În acest exemplu, principiul AI ĂS PI (ISP) nu este respectat deoarece clientul (clasa Manager) foloseşte interfaţa Iworker care conţine mai multe metode decît îi sunt necesare. Pentru a rezolva această problemă, trebuie să plasăm metoda eat într-o altă interfaţă.s
DIP – Dependency Inversion Principle, inversării dependenţei, clasele trebuie să depindă de abstracţii şi nu de implementări.
Metodele de nivel înalt nu trebuie să depindă de cele de nivel jos şi ambele trebuie să depindă de abstracţii.
Abstracţiile nu trebuie să depinde de detalii, ci invers, detaliile de abstracţii. Trebuie să folosim multe interfeţe şi abstracţii.
Principiul DIP spune că dacă o clasă depinde de alte clase, ea ar trebui să utilizeze interfeţe în loc de tipuri (clase concrete), adică ar trebui să izolăm clasa prin abstracţii de care ea depinde. Dacă detaliile în spatele ebstracţiilor se modifică, clasa noastră rămîne neschimbată. Aceasta ne permite să avem o legătura mai slabă (low coupling) între clase.
Exemplul (clasa Worker) violează DIP deoarece clasa Manger (modul de nivel înalt) depinde direct de clasa Worker (modul de nivel jos), şi nu există nici o abstracţie între aceste 2 clase care ar permite clasei manager să fie independentă de modulul de nivel jos. Respectiv, apariţia clasei SuperWorker ne impune să facem modificări în clasa manager pentru ca aceasta să fie susţinută.
Nivel jos – ceea ce realizează funcţionalul;
Nivel înalt – ceea ce ar utiliza nivelul jos;
Principii de proiectare GRASP
Principiile GRASP sunt un set de principii implementate sau aplicate în OOP, care ne permit o dezvoltare mai facilă a soft-ului.
Acronimul GRASP vine de la General Responsibility Assignment Software Patterns. Aceste principii ţin de modul în care sînt distribuite responsabilităţile între clase. Există 2 tipuri de responsabilităţi:
1. De realizare;
2. De cunoaştere;
Resp. de realizare ţin de comportamentul (metodele) claselor şi pot fi stabilite la etapa de modelare (diagrame de interacţiuni ne sugerează aceasta prin mesajele transmise).
Resp. de cunoaştere ţin de datele de care clasa trebuie să le manipuleze.
Există 9 principii:
1. Creator
2. Information Expert
3. Low Coupling
4. Controller
5. High Cohesion
6. Polymorphism
7. Pure Fabrication (invenţie pură)
8. Indirection
9. Protected Variations
Creator
Problemă: Cine ar fi responsabil de crearea instanţei noi unei clase?
Soluţia: Atribuiţi clasei B responsabilitatea de a crea instanţa clasei A dacă unu lasu mai multe puncte de mai jos pot fi aplicate. Dacă mai multe de o opţiune poate fi aplicată, preferaţi clasa B care conţine atributul de tip A.
- B conţine un atribut de tip A.
- B înregistrează A. (el populează datele lui A)
- B ut. foarte mult A; (are multe metode în care are parametri de tip A)
- B are datele de iniţializare ale lui A şi le va transmite obiectului de tip A atunci cînd acesta este creat.
Information Expert
Problemă: Care este principiul general de atribuire a responsabilităţilor la obiect?
Soluţie: Atribuiţi responsabilitatea la expert clasa care are informaţia necesară pentru a îndeplini responsabilitatea.
Acest principiu este unul din cele mai des întîlnite şi este un factor cheie pentru asigurarea cuplării slabe şi coeziunii de nivel înalt.
Low Coupling
Problemă: Cum să asigurăm dependenţele de nivel jos (slabă), impact slab la modificare şi nivel ridicat de reutilizare?
Soluţia: Atribuiţi responsabilitatea astfel încît legături să fie cît mai puţine.
Acest principiu presupune evaluarea tuturor alternativelor şi alegerea celei mai posibile legături. Cuplarea se referă la dependenţele dintre clase, sub-sisteme, sisteme etc. Poate fi împărţită în 2 categorii: slabă (bine)/înaltă (rău).
Cuplarea de nivel înalt poate duce la:
1. Mai multă dificultate în înţelegerea codului.
2. Propagarea excesivă a modificărilor.
3. Mai multe obstacolr în reutilizarea codului.
Controller
Problemă: Care este primul obiect din spatele nivelului UI care primeşte şi coordonează lucrul sistemului?
Soluţia: Atribuiţi această responsabilitate unuia dintre tipurile date de clase:
- Controller Facade – reprezintă sistemul în întregime şi oferă un punct de intrare în sistem. (de văzut şablonul FACADE din Design Patterns).
- Controller UseCase/Sesiune – reprezintă o clasă ce prelucrează mesajul de intrare într-un scenariu.
Un controller încearcă să coordoneze lucrul fără a realiza prea multe. Cuvîntul cheie pentru controller este delgare. Controller-ul primeşte cererea şi hotărăşte ce cui să o transmită mai departe.
Controller-ul este un element care poate fi folosit în implementarea şablonului FACADE. Acest şablon e un punct de intrare în sistem, separînd clientul de detaliile de implementare prin oferirea unei interfeţe publice (care are un timp de viaţă destul de lung),
High Cohesion
Problemă: cum să păstrăm obiectele/clasele focusate, uşor de înţeles şi coordonat şi în acelaşi timp să susţinem principiul low coupling?
Soluţia: atribuiţi responsabilitatea astfel încît legăturile interne să rămîna puternice. Coeziunea se referă la legăturile funcţionale dintre elemente care este o metrică (ex. Timp de încărcare) a focusării responsabilităţilor unui element.
O coeziune mai slabă, în majoritatea cazurilor duce la:
1. Un element va fi mai greu de înţeles, menţinut şi reutilizat;
2. Un element este mai probabil să fie afectat de modificări;
Recomandarea în acest caz este de a găsi locul potrivit în modulul necesar şi/sau utilizarea mai frecventă a delegării.
Polimorfismul
Problema: cum coordonăm soluţiile alternative ce se bazează pe tipul obiectului. Cum să creăm componente software ce pot fi schimbate în timp real?
Soluţia: Cînd alternativele sau comportamentul variază după tipul clasei, atribuim responabilităţile utilizînd operaţii polimorfice. Aceste operaţii vor fi distribuite pe clase diferite, însă vor avea semnături identice.
Pure Fabrication
Problemă: care obiect ar trebui să aibă responsabilitatea atunci cînd nu dorim să violăm High Cohesion şi Low Coupling. Însă, soluţiile oferite de expert nu sunt potrivite.
Soluţia: Atribuiţi un set de responsabilităţi strîns legate unei clase artificiale care nu reprezintă un concept din domeniu, însă va susţine reutilizarea, cuplarea slabă şi coeziunea înaltă.
Exemple de pure fabrication pot fi toate şabloanele de proiectare din lista GOF.
Indirection
Problema: cui trebuie de atribuit resp. pentru a evita cuplarea directă dintre 2 sau mai multe clase? Cum să decuplăm obiectele a.î. să susţinem cuplarea slabă şi să păstrăm reutilizarea la un nivel înalt.
Soluţia: atribuiţi resp. unui obiect intermediar care va media interacţiunile dintre obiectele ce nu sunt cuplate direct .
Foarte des, acest intermediar, este şi el o itenţie pură (pure fabrication). Exemple de indirection sunt şabloanele Adapter, Bridge, Facade, Observer, Mediator.
Protected Variations
Problemă: cum să proiectăm elementele (clase/subsisteme/sisteme) astfel încît variaţiile lor sau instabilitatea cerinţelor faţă de ele să nu aibă un efect nedorit asupra altor elemente.
Soluţia:Identificaţi punctele de instabilitate sau variaţie preconizată. Atribuiţi resp. astfel încît să creaţi o interfaţă stabilă în jurul lor.
Determinarea şi analiza cerinţelor
O cerinţă este o afirmaţie, ceea ce trebuie să facă sistemul, sau un set de caracteristici pe care trebuie să le aibă sistemul.
Este important de a înţelege că cerinţele se pot schimba pe parcursul dezvoltării proiectului.
Există 2 tipuri de cerinţe: funcţionale/non-funcţionale.
C. funcţionale descriu procesele pe care trebuie să le realizeze sistemul şi informaţia pe care acesta trebuie să o conţină. Restul cerinţelor, ce nu intră în descrierea de mai sus, sunt non-funcţionale (ex. Cerinţe operaţionale, de performanţă, de securitate etc).
Surse de cerinţe
1. Clienţii
2. Utilizatori
3. Administratori, personal de mentenaţă
4. Parteneri
5. Experţii în domeniu
6. Analişti ai industriei
7. Informaţii despre concurenţi
Tehnici de colectare a cerinţelor
Abilităţile necesare pentru colectarea cerinţelor:
- Impertinenţa (derzosti)
- Imparţialitatea (a nu ţine partea cuiva)
- Capacitatea de a relaxa constrîngerile (scoaterea constr.)
- Atenţie la detalii
- Schimbarea punctului de vedere
Tehnici:
- Interviurile
- Chestionarele
- Sesiuni JAD
- Prototyping
Prototyping
Prototipizarea este o tehnică de colectare a cerinţelor în care se construieşte o versiune primară a sistemului ce va fi un punct de start pentru colectarea cerinţelor ulterioare.
Tool-uri: Axure
Condiţiile de utilizare a prototipizării:
1) Procesul dat trebuie să fie repetitiv;
2) Este creată o versiune rudimentară a sistemului;
3) Scopul este de a crea specificaţii concrete pentru sistemul final;
4) Există posibilitatea convertirii rapide din cerinţe în sistem funcţional;
5) După ce utilizatorul vede cerinţele implementate în prototip, de regulă, el cere alte modificări.
Cînd este prototip. cea mai utilă:
1. Atunci cînd cerinţele clienţilor nu sînt clare;
2. Sunt implicate puţine persoane în procesul de determinare a cerinţelor;
3. Cînd design-ul grafic este complex şi necesită o formă concretă.
4. Cînd există o istorie a comunicării problematice între clienţi şi dezvoltatori.
5. Există instrumente pentru prototipizare.
Puncte negative ale prototipizării:
1. Tendinţa de a evita documentaţia formalizată.
2. Dificultatea de a adapta prototipul la un grup de utilizatori mai general.
3. Partajarea datelor cu alte sisteme este deseori ignorată.
4. Termenii ciclului de dezv. A soft-ului foarte des nu sunt respectaţi.
Alte tehnici:
- Interviu unul la unul
- Interviu în grup
- Brainstorming
- Interface Analysis (analiza interfeţelor) – obţ. Setul de funcţionalităţi;
- Reverse Engeneering – avem cod sursă, obţinem din el cerinţe/diagrame/structură;
- Study analogous systems (studierea sistemelor analogice) – concurenţii;
Analiza cerinţelor
1. Recunoaşterea problemei (identificarea) – ident. probl. şi vedem dacă este un risc etc.
2. Evaluare şi sinteză – focusarea la ce trebuie de făcut, ci nu cum trebuie;
3. Modelare
4. Specificare
5. Review
Întrebari de management
- Cît de mult efort punem în analiză?
- Ce face analiza?
- De ce este atît de dificil?
- Cine plăteşte?
Studii de fezabilitate (arată dacă proiectul poate/are sens a fi făcut):
- Fez. Economică
- Fez. Tehnică (resurse tehnice)
- Fez. Legală
- Alternative
Specificaţiile sistemului
- Introducere
- Descrierea funcţionalului
- Descrierea sub-sistemelor
- Modelare sistemului şi simularea rezultatelor
- Produse
- Anexe
Validarea cerinţelor
- Este cerinţa corectă sau nu?
- Este cerinţa consistentă?
- Este ea completă?
…
Modelare
CÎnd modelăm sistemul, luăm în consideraţie:
1. Modelul de date care ne arată relaţiile între obiectele sistemului;
2. Modeul funcţional descrie funcţiile care transformă obiectele de sistem şi modelul de comportament, descrie modul în care sistemul răspunde la evenimentele din afară;
3. Modelul de comportament descrie interfeţele de acces la sistem (API-uri etc.);
Principiile de descriere a specificaţiilor
1. Separarea funcţionalităţilor de implementare(atunci cînd specificăm funcţ., nu trebuie să spunem cum le vor realiza);
2. Este necesar a folosi un limbaj de specificare orientat pe procese (ex. UML);
3. Specificaţiile trebuie să conţină componentele software ale sistemului;
4. Specificaţiile trebuie să fie operaţionale (să răspundă la întrebarea CUM TREBUIE ACEASTA SĂ LUCREZE?/CUM TREBUIE REALIZAT?);
5. Trebuie să fie simplu de adăugat specificaţii noi şi în acelaşi timp, lipsa tuturor detaliilor nu trebuie să împiedice înţelegerea sistemului;
6. Specificaţiile trebuie să fie localizate şi cuplate slab;
Review-ul specificaţiilor
1. Revizuirea este realizată de client şi developer;
2. Odată aprobată, specificaţia devine un contract pentru dezvoltarea soft-ului;
3. Specificaţia este dificil de testat în mod logic;
4. Estimarea impactului schimbării de specificaţie este foarte greu de realizat;
Revizuirea cerinţelor
1. Revizuirea obiectivelor şi scopurilor;
2. Comparăm cerinţele ca să corespundă obiectivelor şi scopurilor;
3. Trebuie luat în consideraţie mediul de operare al sistemului;
4. Estimăm şi documentăm toate riscurile în operarea sistemului dezvoltat (atît în regim de producţie cît şi de testare şi dezvoltare);
5. Discutarea procedurilor de testare a cerniţelor;
Erori tipice în analiza cerinţelor
1. Clienţii nu chiar ştiu ceea ce vor;
2. Cerinţele se modifică pe parcursul proiectului;
3. Clienţii cer termeni ne-rezonabili;
4. Există probleme de comunicare între clienţi, ingineri şi manageri de proiect;
5. Echipa de dezvoltare nu înţelege politica organizaţiei clientului;
Etapa de proiectare. Arhitecturi
Definiţie: o arhitectură software cuprinde setul de decizii importante şi deciziile ce ţin de organizarea unui sistem software, incluzînd alegerea elementelor structurale şi a interfeţelor lor; Comportamentul specificat în colaborarea dintre aceste elemente; compoziţia acestor elemente structurale şi de comportament în sub-sisteme mai mari; un stil arhitectural care conduce sau ghidează această organizaţie.
Arhitectura se bazează pe cerinţele deja analizate.
Ca şi orice structură complexă, soft-ul trebuie să aibă un fundament solid. Instrumentele şi platformele moderne ne permit să simplificăm procesul de creare a aplicaţiilor, însă, nu înlocuiesc necesitatea de a proiecta aplicaţia, bazîndu-ne pe cerinţe şi scenarii specifice. Riscul proiectării slabe duce la soft instabil , greu de menţinut şi de dezvoltat.
Вернуться назад »
Категория: Informatica | Просмотров: 529
Похожие новости
"Aniroc Beauty Salon" S.R.LPlan de afacere
"Happy Events” S.R.LPlan de afacere
"Pete albe" în gândirea noastrăPsihologie
Всего комментариев: 0 | |