Documente Academic
Documente Profesional
Documente Cultură
Practica - Felea-Gheorghies PDF
Practica - Felea-Gheorghies PDF
FACULTATEA DE INFORMATICĂ
DEPARTAMENTUL DE ÎNVĂŢĂMÂNT LA DISTANŢĂ
VICTOR FELEA
ADRIANA GHEORGHIEŞ
OVIDIU GHEORGHIEŞ
PRACTICĂ
2006-2007
Practică – Modul I
Note de curs
Formatul general pentru sistemul de gestiune de baze de date FOX pentru DOS sau
WINDOWS este:
ALL
SELECT exp1[AS c1], ..., expq[AS cq]
DISTINCT
INTO <destinaţie>
TO FILE <nume fişier>[ADDTITIVE]
TO PRINTER
(exp1( v α1 ...αh ), ..., expq( v α1 ...αh )). Componenta WHERE serveşte la filtrarea acestor linii: se
PRACTICĂ Prof.dr.Victor Felea Pag.4
Asist.drd.Ovidiu Gheorghieş
evaluează <expresie logică1> pentru vectorul v α1 ...αh , notată <expresie logică1>( v α1 ...αh ). Dacă
rezultatul este .F., atunci linia L α ...α este ignorată în continuare, altfel ea este considerată.
1 h
Ieşirea comenzii va fi formată dintr-o tabelă cu q coloane (câmpuri sau atribute). Dacă pentru
expresia de număr j se precizează expj AS cj, atunci cj este un nume atribuit coloanei j din
tabela rezultată(de ieşire). Această coloană primeşte caracteristicile expresiei expj
(identificator, tip, lungime, număr de zecimale). Dacă pentru expresia expj nu se precizează
AS cj, atunci numele coloanei de număr j şi caracteristicile ei se atribuie după anumite reguli
(numite reguli standard), precizate in continuare.
a) Dacă expj este formată numai din <cimp> ce apare o singură dată în lista expresiilor
de ieşire, atunci coloana j a tabelei va avea numele <cimp> şi caracteristicile acestuia.
b) Dacă expj este formată numai din <cimp>, ce apare de mai multe ori în lista
expresiilor de ieşire (poate fi precedat de alias-uri diferite), atunci pentru prima apariţie
numele coloanei va fi <cimp_A>, pentru a doua <cimp_B>, etc.
c) Dacă expj este diferită de <cimp>(conţine în afara de <cimp> şi alte elemente),
atunci pentru prima apariţie a unei astfel de expresii se consideră identificatorul EXP_A,
pentru a doua EXP_B, etc.
d) Dacă expj are forma SUM(expresie), atunci pentru prima apariţie a acesteia,
identificatorul coloanei va fi SUM_A, pentru a doua SUM_B, etc. În mod similar, pentru
celelalte funcţii agregat.
Dacă comanda SELECT, va crea o tabelă, atunci vom da componenta INTO DBF <nume
tabelă_ieşire>. La terminarea comenzii tabela de ieşire rămâne activă în zona curentă, deci
utilizând DISP STRU putem vizualiza numele şi caracteristicile câmpurilor de ieşire. Tabelele
de intrare T1, ..., Th sunt activate, la interpretarea comenzii SELECT-SQL în zone de lucru
libere, iar la terminarea normală a comenzii sunt închise.
Rezultă că singurele componente obligatorii ale comenzii SELECT – SQL sunt: lista
expresiilor de ieşire şi componenta FROM.
În cazul în care comanda SELECT- SQL are în plus numai componenta WHERE<expresie
logică1>, atunci executarea ei se realizează astfel:
FOR α1 = 1 TO m1
....
FOR αh = 1 TO mh
- se evaluează <expresie logică1>( v α1 ...αh ), fie w–valoarea rezultată,
- IF(w)
FOR i = 1 TO q
- se evaluează expi( v α1 ...αh ), fie wi – valoarea rezultată,
ENDFOR
- se plasează la ieşire L α ...α =(w1, ...,wq)
1 h
ENDIF
ENDFOR αh
....
ENDFOR α1
Componenta <destinaţie> are următoarele forme sintactice:
1) ARRAY <numetablou>
2) CURSOR <numetabelă>
3) DBF <numetabelă>
4) TABLE <numetabelă>
PRACTICĂ Prof.dr.Victor Felea Pag.5
Asist.drd.Ovidiu Gheorghieş
In cazul 1) o linie de ieşire L α ...α =(w1, ...,wq) va fi înregistrată într-o linie a tabloului
1 h
( ) ( ) ( )
.T. dacă a i .cimp1 v α1 ...α h θ a j .cimp 2 vα1 ...α h ,
e v α1 ...α h =
.F. altfel.
Deci, pe scurt, semantica expresiei e pentru v α1 ...αh este: expresia e este TRUE, dacă valorile
înregistrărilor respective pentru cimp1 şi cimp2 sunt în relaţia θ.
În privinţa comparării a două şiruri de caractere s1 şi s2 există diverse situaţii pentru valoarea
de adevăr a expresiei s1θs2, unde θ este operator de comparare. De exemplu SET EXACT ON
implică în cazul s1 = s2, valoarea TRUE, dacă cele două şiruri au aceeaşi lungime şi acelaşi
caractere. Dacă avem SET EXACT OFF, atunci s1=s2 este TRUE dacă valoarea unui şir este
prefix al valorii celuilalt.
b) e = ai.cimp θ expresie, unde expresie nu este formată numai dintr-un câmp.
Valoarea expresiei e pentru v α1 ...αh este:
( ) ( ) ( )
.T. dacă a i .cimp v α1 ...αh θ exp resie vα1 ...α h ,
e v α1 ...αh =
.F. altfel.
c) e = ai.cimp θ ALL (SELECT cimp2 FROM T2...).
Expresia după cuvântul rezervat ALL se numeşte subselecţie.
În general, vom numi subselecţie o frază SELECT inclusă între paranteze rotunde. Aici
subselecţia are o singură expresie de ieşire: cimp2. Rezultatul subselecţiei va fi o tabelă T' cu
un singur atribut. Fie T' cu m linii şi w1, ..., wm valorile atributului de ieşire pentru cele m
linii. Identificatorii cimp1 şi cimp2 trebuie să fie de acelaşi tip. Valoarea expresiei e pentru
vectorul v α1 ...αh de înregistrări este:
( )
e v α1 ...αh =
( )
.T. dacă a i .cimp v α1 ...αh θ w i , ∀i = 1, m,
.F. altfel.
c') e = ai.cimp1 θ ALL (SELECT exp2 FROM T2...).
exp2 este o expresie de acelaşi tip cu cimp1. Evaluarea este similară ca în cazul c) considerând
exp2 în loc de cimp2.
PRACTICĂ Prof.dr.Victor Felea Pag.6
Asist.drd.Ovidiu Gheorghieş
ANY
d) e = ai.cimp1 θ (SELECT cimp2 FROM T2...).
SOME
Folosind notaţiile de la c), definim:
( )
e v α1 ...αh =
( )
.T. dacă ∃i,1 ≤ i ≤ m, astfel încât a i .cimp1 vα1 ...αh θ w i ,
.F. altfel.
ANY
d') e = ai.cimp1 θ (SELECT exp2 FROM T2...).
SOME
exp2 este o expresie de acelaşi tip cu cimp1. Evaluarea este similară ca în cazul d).
e) e = ai.cimp [NOT] BETWEEN exp1 AND exp2.
Atributul cimp trebuie să aibă acelaşi tip cu expresiile exp1 şi exp2. Fără cuvântul rezervat
NOT, evaluarea lui e va fi:
( )
e v α1 ...αh =
( )
.T. dacă a i .cimp v α1 ...αh este în intervalul de valori [exp1 , exp 2 ],
.F. altfel.
Expresia cu NOT înseamnă o evaluarea inversă ca mai sus.
f) e = [NOT] EXISTS ( SELECT exp1, ..., expq FROM ...).
Fie T' tabela ce constituie rezultatul subselecţiei. Fără cuvântul NOT evaluarea este definită
prin:
.T. dacă T ' ≠ ∅ (T' are cel puţin o înregistrare),
( )
e v α1 ...αh =
.F. altfel.
Dacă există cuvântul NOT, atunci:
.T. dacă T ' = ∅,
( )
e v α1 ...αh =
.F. altfel.
Obs. Evaluarea tabelei T' poate fi independentă de vectorul v α1 ...αh (adică are aceeaşi valoare
pentru fiecare element al produsului cartezian T1 × ...× Th), sau dependentă de v α1 ...αh .
Exemplul 1: Fie tabela PERSONAL cu câmpurile MARCA – cheie unică şi NUME,
PRENUME, SALARIU, SECŢIE, şi tabela VANZARI cu câmpurile MARCAV – marca
persoanei ce vinde, CODSV – codul sectiei în care se vinde produsul respectiv, CODPV –
codul produsului vândut, CANTV – cantitatea vândută de MARCAV din produsul CODPV.
Fie tabela PRODUS cu câmpurile CODP – codul produsului (cheie unică), DENP –
denumire, PRET – preţul unitar.
Fie interogarea:
I) Să se afişeze vânzările realizate de persoanele înregistrate în tabela PERSONAL sub forma:
MARCAV, CODPV, CANTV
O comandă SELECT – SQL, ce realizează interogarea, poate fi:
FROM VANZARI A;
WHERE EXISTS;
Notând cu T' tabela definită de subselecţie, se observă că T' depinde de valorile câmpului
A.MARCAV, deci subselecţia este dependentă de v α = (Iα), unde 1 ≤ α ≤ m1 şi vectorul de
înregistrări al tabelei VANZARI este (I1, ..., I m1 ).
Deoarece MARCA este cheie unică, rezultă că T' are fie o singură înregistare, fie T' = ∅.
II) Fie interogarea: să se afişeze vânzările realizate de persoane care nu există în PERSONAL.
FROM VANZARI A;
III) Să se găsească persoanele din PERSONAL, care vând produsul cu codul 'P1'.
WHERE EXISTS;
(B.CODPV = 'P1') )
FROM VANZARI A;
( )
e v α1 ...α h =
( )
.T. dacă a j .cimp v α1 ...αh ∈ {w1 ,..., w m } ;
.F. altfel.
( )
Dacă există NOT, atunci e v α1 ...αh este inversa celei de mai sus.
Exemplul 2: Considerăm tabelele PERSONAL şi VANZARI definite mai sus. Se cere să se
afişeze persoanele (MARCA, NUME şi PRENUME) care au cel puţin o operaţie de vânzare.
FROM PERSONAL A;
INTO DBF F1
.F. altfel.
Deoarece în FOX sunt permise numai astfel de expresii pentru q = 1, atunci pentru q > 2,
putem proceda astfel:
a) Fie situaţia când toate aj.cimpj sunt de tip caracter (la fel şi bj.cimp'j). Putem
construi următoarea expresie:
e1 = (a1.cimp1+...+ aq.cimpq) [NOT] IN (SELECT b1 .cimp1′ + ... + b q .cimp′q ... ).
Avem e1( v α1 ...αh ) = e( v α1 ...αh ).
b) În cazul când aceste câmpuri nu sunt de tipul caracter se folosesc funcţiile de
conversie (STR, DTOC) pentru conversia la tipul C.
i) e = aj.cimp [NOT] LIKE <expresie sablon>
aj.cimp trebuie să fie de tip C, deoarece <expresie sablon> defineşte o mulţime de cuvinte:
caracterul % din expresia şablon reprezintă orice cuvânt, iar caracterul '_' reprezinta orice
caracter.
Exemplul 5. <expresie şablon> = ALFA% înseamnă toate cuvintele ce încep cu caracterele
ALFA.
Fie M mulţimea cuvintelor definite de <expresie şablon>.
Fără NOT valoarea expresiei e pentru v α1 ...αh este:
( )
e v α1 ...αh =
( )
.T. dacă a j .cimp v α1 ...αh ∈ M,
.F. altfel.
O condiţie oarecare ce poate apare în componenta WHERE se defineşte cu ajutorul
operatorilor AND, OR şi NOT. Rezultă că avem următoarele reguli pentru definirea unor
condiţii:
1. orice condiţie elementară este o condiţie.
2. dacă e1 şi e2 sunt condiţii, atunci e1 AND e2, (e1 AND e2), e1 OR e2, (e1 OR e2),
NOT e1, ( NOT e1) sunt condiţii.
3. orice condiţie se obţine numai prin regulile 1 şi 2.
Deoarece condiţiile elementare c, c', d, d', f, h au subselecţii, rezultă necesitatea definirii
nivelelor de selecţie.
1) Cuvântul SELECT, primul din fraza SELECT se consideră pe nivelul 1 şi spunem
că iniţiază o selecţie de nivel 1.
2) Dacă luăm condiţiile elementare c, c', d, d', f, h pentru fraza SELECT de nivel 1,
spunem că orice verb SELECT din subselecţii este pe nivelul 2 şi defineşte o selecţie de nivel
2.
3) Fie cuvântul SELECT situat pe nivelul h şi în componenta WHERE
corespunzătoare avem o subselecţie de tipul c, c', d, d', f, sau h. Atunci spunem că această
subselecţie este de nivelul h + 1.
4) Cuvântul UNION se aplică numai la selecţii de nivel 1, deci SELECT ce urmează
lui UNION este considerat de nivel 1.
5) Pot exista, în general, mai multe selecţii pe un acelaşi nivel s.
PRACTICĂ Prof.dr.Victor Felea Pag.10
Asist.drd.Ovidiu Gheorghieş
6) În FOX pot exista maxim 2 nivele de selecţie, pe când în SGBD – ORACLE sau
DB2 practic, până la 50 nivele de selecţie.
Să considerăm acum componentele GROUP BY şi HAVING.
Componenta GROUP BY are forma:
GROUP BY grup1, ..., grupp, unde grupj sunt fie câmpuri ce apar în lista expresiilor de ieşire,
fie sunt numere naturale cuprinse între 1 şi q (numărul total al coloanelor de ieşire), ce
reprezintă numere de coloane.
Folosirea cuvântului ALL ce urmează cuvântului SELECT înseamnă considerarea tuturor
liniilor rezultate în urma interpretării componentei WHERE, iar folosirea lui DISTINCT
t1
t
înseamnă eliminarea liniilor duplicate. Să notăm cu M mulţimea acestor linii. Fie M = 2 ,
M
tm
unde tj sunt liniile de ieşire,
1 ≤ j ≤ m.
Se evaluează grup1 pentru toţi tj, 1 ≤ j≤ m, fie grup1(tj) valoarea lui grup1 pentru linia tj. Fie
{ }
M1 ={ grup1(tj), 1 ≤j ≤m}= v1 ,..., v m1 . Se împarte mulţimea de linii M în clase, notate
1
C ,..., C
1
1
m1 câte o clasă pentru fiecare valoare vi din M1, 1 ≤i≤m1, anume:
C1i = {t α | t α ∈ M, grup1 ( t α ) = vi } . Deci clasa C1i este formată din toate liniile lui M ce au
aceeaşi valoare vi pentru câmpul grup1.
Exemplul 6. Pentru tabela VANZARI ne interesează pentru fiecare valoare a câmpului
MARCAV, care este valoarea de vânzare respectivă.
WHERE A.CODPV=B.CODP;
GROUP BY A.MARCAV;
INTO DBF F1
1 100 56
2 200 60
Evident dacă Ci1 şi C1j sunt două clase diferite (i≠j), atunci rezultă că vi ≠ vj, deci clasele sunt
disjuncte. Avem şi faptul că ele sunt nevide, deci C11 ,..., Cm1 1 este o partiţie a lui M.
Procedăm inductiv. Presupunem că, după considerarea lui grupj, s-a obţinut o partiţie a lui M
j j
în clasele C1 ,..., Cm j (j <p).
j
Fie acum considerarea lui grupj+1. Fiecare clasă Cs se rafinează conform grupului grupj+1
exact în aceeaşi manieră cum M s-a rafinat conform grupului grup1. Fie rafinarea obţinută
j s s
astfel a lui Cs prin grupj+1 notată T1 ,..., Tps , 1≤ s≤mj. Atunci rafinarea lui M în clase
1 1 2 2 m m
considerând grup1, ..., grupj+1 va fi: T1 ,..., Tp1 , T1 ,..., Tp2 , T1 j ,..., Tpm j . Fie aceste clase
j
mj
j +1 j +1
renotate prin: C1 ,..., Cm j +1 unde m j +1 = ∑p s =1
s . Astfel, după considerarea tuturor grupurilor
p p
grup1,..., grupp, obţinem rafinarea lui M în clasele C1 ,..., Cm p . Rezultă următoarea
proprietate a acestor clase:
Toate uplele unei clase au aceleaşi valori pentru câmpurile grup1, ..., grupp, ceeace se exprimă
p
prin: (∀ t1, ∀t2) {t1, t2∈ C j ⇒ t1 [ grup1 ,...,grup p ] =
t2[ grup1 ,...,grup p ]}, pentru orice j, 1 ≤ j≤ mp, parantezele [, ] reprezentând proiecţia. Două
uple din clase distincte au vectori de valori distincţi pentru grup1 ,...,grup p .
Expresiile de ieşire ale comenzii SELECT: exp1, ..., expq pot conţine funcţii de grupare:
COUNT, MIN, MAX, SUM, VAR, ce se vor aplica asupra claselor definite de componenta
GROUP BY. In acest caz, rezultă că numărul de uple ale tabelei de ieşire este egal cu numărul
de clase, deci mp.
Exemplul 7. Să se afişeze pentru fiecare valoare a câmpului MARCAV din VANZARI,
numărul de vânzări realizate:
FROM VANZARI A;
GROUP BY A.MARCAV;
INTO DBF F1
ON A.MARCA = B.MARCAV
Rezultatul:
MARCA NUME CODPV
PRACTICĂ Prof.dr.Victor Felea Pag.14
Asist.drd.Ovidiu Gheorghieş
100 A P1
100 A P2
100 A P3
300 C P1
300 C P2
ON A.MARCA = B.MARCAV
d) În cazul în care folosim FULL OUTER JOIN între cele două tabele, atunci rezultatul va fi
format din liniile de la a), la care se adaugă cele în plus de la b) şi c).
Cuvântul rezervat NULL semnifică valoarea nedefinită (un câmp nu este iniţializat). El poate
să apară în comanda CREATE TABLE, ce are forma:
NULL
CREATE TABLE <nume tabelă> (cimp1 tip1 , ...)
NOT NULL
Apariţia NOT NULL pentru cimp1 specifică faptul că toate înregistrările trebuie să fie definite
pentru cimp1, deci cimp1 trebuie să aibă valoare pentru toate înregistrările, iar NULL – cazul
contrar. tip1 este tipul atributului cimp1.
PRACTICĂ Prof.dr.Victor Felea Pag.15
Asist.drd.Ovidiu Gheorghieş
Cuvântul NULL poate să apară în expresii aritmetice ca operand, rezultatul este evaluat la
NULL. De asemenea, el poate apare în expresii logice ca operand. Aceste expresii au forma:
IS
<operand1> <operand2>, unde <operand1> sau <operand2> este cuvântul NULL.
IS NOT
Rezultă de aici considerarea, pe lângă valorile de adevăr TRUE, FALSE şi a unei alte valori,
notată UNKNOWN.
Ca un exemplu, expresia <cimp is NULL> evaluată pentru o înregistrare I are valoarea .T.,
dacă avem cimp(I) este nedefinit şi .F. altfel.
Expresia <cimp = NULL> are valoarea UNKNOWN, indiferent dacă avem cimp(I) definit
sau nedefinit. Valoarea UNKNOWN, notată pe scurt U, este considerată între valorile
TRUE(.T.) şi FALSE(.F.).
Conjuncţia şi disjuncţia a 2 valori logice se defineşte astfel:
X Y X AND Y X OR Y
.T. .T. .T. .T.
.T. U U .T.
.T. .F. .F. .T.
U .T. U .T.
U U U U
U .F. .F. U
.F. .T. .F. .T.
.F. U .F. U
.F. .F. .F. .F.
x NOT x
.T. .F.
U U
.F. .T.
Funcţiile de grupare (SUM, MIN, MAX, COUNT, AVG) nu consideră expresiile cu valoarea
NULL. Dacă o expresie aritmetică sau relaţională are pentru vectorul v α1 ...αh un operand cu
valoarea NULL, atunci expresia are valoarea NULL.
S1 S2 S3
T1 T2 T3 T4 T5 T6
F1 F2 F3 F4 F5 F6
A.SECTIE, A.MARCASEF
FROM PERSONAL A
A.SECTIE, A.MARCASEF
FROM PERSONAL A
FROM PERSONAL A
FROM PERSONAL A
FROM PERSONAL A
FROM PERSONAL A
(A.NUME ! = 'T5')
PRACTICĂ Prof.dr.Victor Felea Pag.20
Asist.drd.Ovidiu Gheorghieş
START WITH A.NUME = 'S3'
FROM PERSONAL A
FROM PERSONAL A
Rezultatul:
0 90 T5
1 140 F4
1 150 F5
1 160 F6
Fraza SELECT poate conţine componenta GROUP BY şi funcţii de grupare:
9) Să se afişeze pentru subordonaţii lui 'P', suma salariilor pe fiecare nivel din
arborescenţa cu rădăcina P.
FROM PERSONAL A
PRACTICĂ Prof.dr.Victor Felea Pag.21
Asist.drd.Ovidiu Gheorghieş
CONNECT BY PRIOR A.MARCA = A.MARCASEF
GROUP BY LEVEL
ORDER BY LEVEL
10) Să se afişeze pentru toţi subordonaţii lui 'S1', suma salariilor din fiecare secţie.
FROM PERSONAL A
GROUP BY A.SECTIE
ORDER BY A.SECTIE
WHERE A.MARCA IN
Exemplificăm câteva interogări complexe, care necesită utilizarea limbajului intermediar Lint.
Fie tabela VANZARI cu câmpurile MARCAV, CODSV – codul secţiei, CODPV – codul
produsului vândut, CANTV – cantitatea vândută şi tabela SECTII cu câmpurile: CODS –
codul secţiei, DENS – denumirea secţiei, ETAJ – etajul corespunzător secţiei. Fie date
următoarele interogări în Lnat:
1) Se găsească toate persoanele (MARCA, NUME, PRENUME) din tabela
PERSONAL, cu proprietatea că persoana respectivă vinde cel puţin un produs la toate secţiile
existente în tabela SECTII.
2) Să se găsească toate persoanele (MARCA, NUME, PRENUME) din tabela
PERSONAL, care vând cel puţin două produse la toate secţiile de la etajul 2 şi vând cel puţin
2 produse numai la secţiile de la etajul 2 (la alte secţii nu vând cel puţin 2 produse, adică nu
vând nimic sau vând un singur produs).
Să separăm 2 cazuri în ceea ce priveşte interogarea în limbaj natural: cazul când interogarea
nu implică utilizarea funcţiilor de grupare(i) şi desigur cazul contrar(ii).
(i).Să considerăm situaţia când interogarea nu implică funcţii de grupare. Atunci fraza
SELECT va trebui să conţină componenta de intrare, componenta de ieşire şi componenta
WHERE. Să notăm prin I(T1 a1, ..., Th ah) componenta de intrare a comenzii SELECT, unde
Tj, 1 ≤j ≤ h sunt tabelele de intrare, iar aj este aliasul local al tabelei Tj, 1 ≤j ≤ h. Tabelele Tj
nu trebuie neapărat să fie distincte, dar obligatoriu aliasurile aj sunt distincte.
Notăm prin O(exp1 col1, ..., expq colq) ieşirea comenzii SELECT, unde expi, 1 ≤ i ≤ q sunt
numele expresiilor de ieşire, iar coli este numele atribuit pentru câmpul de ieşire de număr i, 1
≤ i ≤ q.
Referirea la <cimp> definit în tabela Tj se va face prin <aj.cimp>. Notăm prin W<expresie
logică> componenta WHERE a frazei SELECT.
Forma generală a unei expresii în limbajul Lint va fi:
E ≡ I(T1 a1, ..., Th ah) O (exp1 col1,..., expq colq) W<expresie logică>.
PRACTICĂ Prof.dr.Victor Felea Pag.23
Asist.drd.Ovidiu Gheorghieş
Rămâne de exprimat <expresie logică> în limbajul Lint.
Să notăm prin TRAN(E) transformata expresiei E într-o frază SELECT. Avem TRAN(E):
Vom defini expresii în limbajul Lint şi pentru fiecare E ∈ Lint, definim TRAN(E), care va fi în
general o secvenţă (subcuvânt) al unei fraze SELECT. Pentru unele expresii E, TRAN(E) va
fi o expresie elementară a componentei WHERE a frazei SELECT.
Expresiile limbajului intermediar Lint sunt următoarele:
1) E ≡ aj.cimp ∈(T aj), în care T este o tabelă cu aliasul local aj, iar cimp este definit în
tabela T.
Semantica expresiei E: cimp este definit în T (apare în structura lui T). Definim TRAN(E)
astfel:
Se remarcă faptul că TRAN(E) reprezintă mulţimea valorilor pentru cimp din conţinutul
curent al tabelei T.
2) E ≡ (a1.cimp1, ..., am.cimpm) ∈ (T1 a1)× ...×(Tm am), unde Ti, 1 ≤ i ≤ m sunt tabele,
ai este aliasul lui Ti, 1 ≤ i ≤ m, iar cimpi este definit în tabela Ti,
1 ≤ i ≤ m.
Semantica expresiei E este: cimpi este definit în tabela Ti, 1≤i≤m. Transformarea expresiei E
ca segment al frazei SELECT va fi TRAN(E):
FROM T1 a1,..., Tm am
3) E ≡ (a α1 .cimp1, ..., a α m .cimpm) ∈ (T1 b1)× ...×(Tq bq), unde Ti, 1 ≤ i ≤ q sunt tabele,
bi este aliasul lui Ti, 1 ≤ i ≤ q, a α j , 1 ≤ j ≤ m sunt alias-uri, astfel încât: a α j ∈{b1,..., bq},
j = 1, m . Evident, bi sunt distincte, i = 1, q . Dar a α j pot să coincidă. Dacă a α j = bi, atunci i
este unic şi cimpj este definit în tabela Ti. Expresia de forma 3) este mai generală decât cea de
forma 2), permiţând în lista de câmpuri să apară mai multe câmpuri definite în aceeaşi tabelă.
Semantica expresiei E este: cimpj este definit în tabela Ti, unde i are proprietatea a α j = bi.
Reprezentarea expresiei E ca segment al unei fraze SELECT, notată prin TRAN(E) va fi:
FROM T1 b1,...,Tq bq
PRACTICĂ Prof.dr.Victor Felea Pag.24
Asist.drd.Ovidiu Gheorghieş
4) E ≡ aj.cimp τ{ (T b) [b.cimp']∧E1}
Variabila cimp este definită într-o tabelă cu aliasul aj, T este o tabelă cu aliasul b, iar cimp'
este un câmp definit în tabela T, E1 este o expresie în limbajul intermediar, care conţine drept
cîmpuri numai cele din T. Operatorul τ este diferit de operatorul ∈, deoarece va avea o altă
semantică. Dacă v α1 ...αh este vectorul curent de înregistrări, pentru care se evaluează această
expresie, atunci să notăm cu v1 valoarea lui aj.cimp pentru acest vector, adică v1 =
aj.cimp( v α1 ...αh ). Să notăm cu E( v α1 ...αh ) valoarea expresiei E pentru vectorul v α1 ...αh . Atunci
definim:
TRUE dacă v1 ∈ σE1 ( T ) [cimp']
E( v α1 ...αh ) =
FALSE altfel
Expresia σ E1 ( T ) notează operatorul de selecţie σ din algebra relaţională, aplicat lui T cu
expresia de selecţie E1. Expresia σ E1 ( T ) [cimp'] notează proiecţia lui σ E1 ( T ) pe atributul
cimp'. Transformarea expresiei E ca segment al frazei SELECT (de astă dată va fi o condiţie
elementară a componentei WHERE a frazei SELECT) este definită astfel:
WHERE TRAN{E1}).
În continuare definim o expresie similară cu cea de tipul 4), dar mai generală:
5) E ≡ (a1.cimp1,..., am.cimpm) τ {(T1 b1)× ...×(Tm bm) [ b1.cimp1′ ,..., b m .cimp′m ]∧E1},
unde Ti sunt tabele cu aliasul bi, i = 1, m , bi .cimp′i este un atribut definit în tabela Ti, 1 ≤ i ≤
m, iar aj.cimpj este un câmp definit în tabela cu aliasul aj, j = 1, m . E1 este o expresie în Lint
care conţine drept cîmpuri numai cele din Ti, în particular poate fi o condiţie join.
Semantica expresiei E este: vectorul valorilor curente pentru ai.cimpi, i = 1, m aparţine
mulţimii definite de produsul cartezian al tabelelor T1, ..., Tm filtrat de E1 şi proiectat pe
atributele cimp1′ ,..., cimp′m . Ca şi în cazul 4), pentru vectorul de înregistrări curent v α1 ...αh
definim E( v α1 ...αh ), deci valoarea expresiei E pentru acest vector.
Fie vectorul de valori w= (w1, ..., wm), unde wi = ai.cimpi( v α1 ...αh ), i = 1, m , deci wi este
valoarea atributului ai.cimpi pentru v α1 ...αh .
Fie M= T1 × T2 × ... × Tm, produsul cartezian al conţinutului curent al tabelelor Tj, j = 1, m .
Definim:
TRUE dacă w ∈ σE1 ( M ) [b1.cimp1′ ,..., b m .cimp′m ]
E( v α1 ...αh ) =
FALSE altfel
unde σ E1 ( M ) notează operatorul de selecţie σ, aplicat lui M cu expresia de selecţie E1, iar
σ E1 ( M ) [b1.cimp1′ ,..., b m .cimp′m ] notează proiecţia relaţiei σ E1 ( M ) pe atributele
b1.cimp1′ ,..., b m .cimp′m . Transformarea lui E ca segment al frazei SELECT, care va fi o
condiţie elementară a componentei WHERE (ca şi în cazul 4), se realizează prin:
TRAN{E1}).
6) Considerăm tot operatorul τ, dar cu o expresie mai generală decât cea de la punctul
5).
E ≡ (a1.cimp1, ..., am.cimpm) τ {(T1 b1)× ...×(Tq bq) [ bi1 .cimp1′ ,..., bim .cimp′m ]∧E1}
unde Tj sunt tabele, j = 1, q , cu aliasurile bj, respectiv; bi j .cimp′j este un câmp definit în
tabela Ti j , j = 1, m , deci ij∈{1, 2, ...,q}, j = 1, m . Aliasurile b1, ...,bq sunt distincte, iar aj.cimpj
este un atribut definit într-o tabelă de alias aj, j = 1, m . E1 este o expresie in Lint care contine
drept cimpuri numai cele din Tj, in particular poate fi o conditie join.
Definim valoarea expresiei E pentru vectorul curent de înregistrări v α1 ...αh . Fie w = (w1,
..,wm), unde wi = ai.cimpi( v α1 ...αh ), i = 1, m şi M = T1× ...× Tq, produsul cartezian al tabelelor Ti,
i = 1, q .
TRUE dacă w ∈ σ E1 ( M ) [bi1 .cimp1′ ,..., bim .cimp′m ]
E( v α1 ...αh ) =
FALSE altfel
σ E1 ( M ) notează operatorul de selecţie σ, aplicat lui M cu expresia de selecţie E1. Prin
σE1 (M)[ bi1 .cimp1′ ,..., bim .cimp′m ] se notează proiecţia mulţimii σE1 (M) pe
câmpurile bi1 .cimp1′ ,..., bim .cimp′m . Atât in cazul 5), cât şi în cazul 6) trebuie ca tip(aj.cimpj) =
tip( bi j .cimp′j ), j = 1, m , iar pentru 4) tip(aj.cimp) = tip(b.cimp').
Transformarea lui E ca segment al frazei SELECT, care va fi o condiţie elementară a
componentei WHERE, este următoarea:
Ca şi în cazul 5), TRAN(E) este echivalentă cu o condiţie elementară exprimată prin EXISTS.
Expresia 6) permite ca mai multe câmpuri de forma bi j .cimp′j să fie definite în aceeaşi
tabelă.
7) E ≡ (∃ aj.cimp) [aj.cimp∈(T aj)∧E1]
T este o tabelă de alias aj, cimp este definit în tabela T, iar E1 este o altă expresie în limbaj
intermediar. Simbolul ∃ este cuantificatorul de existenţă.
Semantica expresiei E este: expresia E este adevărată, dacă există o valoare pentru aj.cimp
între valorile tabelei T proiectate pe aj.cimp, astfel încât să fie satisfăcută expresia E1.
Presupunând că am definit TRAN(E1), atunci transformata expresiei E este următoarea:
FROM T aj
WHERE TRAN(E1))
FROM VANZARI B
WHERE TRAN(E2))
PRACTICĂ Prof.dr.Victor Felea Pag.27
Asist.drd.Ovidiu Gheorghieş
TRAN(E) ≡ SELECT A.MARCA, A.NUME, A.PRENUME
FROM PERSONAL A
WHERE TRAN(E1)
FROM PERSONAL A
FROM VANZARI B
8) E ≡ ∃ (a1.cimp1, ..., am.cimpm)[ a1.cimp1∈ (T1 a1) ∧ ... ∧ am.cimpm∈ (Tm am) ∧ E1]
Semantica lui E este: există un vector de valori pentru a1.cimp1, ..., am.cimpm, astfel încât să
fie satisfăcută expresia E1. Variabila aj.cimpj este definită în tabela tj cu aliasul aj, 1 ≤ j ≤ m.
Evident expresia E1 poate depinde de variabilele aj.cimpj, 1 ≤ j ≤ m. Câmpurile aj.cimpj, 1≤ j ≤
m se mai numesc variabile individuale ale expresiei E. Transformarea lui E în limbajul LSEL
va fi o expresie elementară a componentei WHERE:
FROM Tβ b1,...., Tβ
1 P
bp
WHERE TRAN(E1) )
unde b1, ..., bp sunt aliasurile distincte din şirul a1, ..., am. Pentru fiecare aj există un unic bk, cu
proprietatea aj = bk; în acest caz aj.cimpj este definit în tabela Tβk cu aliasul bk. Este deci
posibil, ca mai multe atribute să fie definite în aceeaşi tabelă. Desigur că, o aceeaşi tabelă
poate să apară de mai multe ori în componenta FROM, dar cu alias-uri diferite.
Să specificăm formal semantica expresiei E pentru vectorul de înregistrări curente v α1 ...αh . În
general, expresia E1 depinde de a1.cimp1, ..., am.cimpm şi de v α1 ...αh . Dacă vj este o valoare de
tip egal cu tipul lui aj.cimpj, atunci E1 se evaluează pentru v1, ..., vm şi v α1 ...αh . Să notăm
rezultatul acestei evaluări cu E1(v1, ..., vm, v α1 ...αh ). Evaluarea expresiei E pentru vectorul
curent v α1 ...αh o vom defini prin:
PRACTICĂ Prof.dr.Victor Felea Pag.28
Asist.drd.Ovidiu Gheorghieş
( )
TRUE, dacă ∃v j ∈ Tj[a j .cimp j ], j = 1, m a.î. E1 v1 ,..., v m , vα1 ...α h = TRUE
E( v α1 ...αh ) =
FALSE altfel
Notaţia T[aj.cimpj] specifică proiecţia tabelei T pe aj.cimpj, j = 1, m .
9) E ≡ (∀aj.cimp)[aj.cimp∈ (T aj)⇒ E1]
aj.cimp este un atribut definit în tabela T cu aliasul aj, simbolul ∀ este cuantificatorul
universal, iar simbolul "⇒" este implicaţia logică. E1 este o expresie a limbajului Lint.
Semantica lui E este următoarea: E este adevărată dacă pentru orice valoare a câmpului
aj.cimp din tabela T, avem adevărată expresia E1. Formal, această semantică o vom exprima
astfel: fie v α1 ...αh vectorul de înregistrări curente la care se aplică E. Expresia E1 depinde de
aj.cimp şi de vectorul de înregistrări v α1 ...αh .
Să notăm cu E1(v, v α1 ...αh ) valoarea expresiei E1 pentru valoarea v a câmpului aj.cimp şi pentru
vectorul de înregistrări v α1 ...αh . Valoarea lui E pentru v α1 ...αh , notată E(vα1 ...αh ) va fi definită
astfel:
( )
TRUE, dacă pentru ∀v ∈ T[a j .cimp], avem E1 v, v α1 ...αh = TRUE
E( v α1 ...αh ) =
FALSE altfel
Notaţia T[aj.cimp] specifică proiecţia tabelei T pe câmpul aj.cimp.
Pentru exprimarea expresiei E în limbajul LSEL, va trebui să transformăm formula E cu
cuantificatorul "∀" într-o formulă echivalentă ce utilizează cuantificatorul "∃", deoarece în
LSEL putem exprima numai cuantificatorul "∃", prin expresii elementare de forma: EXISTS
(SELECT ...).
Formula din limbajul Lint de forma E ≡ (∀x)[F ⇒ E1] este echivalentă cu (∀x)[(F ∨E1)]≡
(∀x)[(F ∨E1)] ≡(∃ x)[F ∧ E1]. Rezultă că transformarea lui E în limbajul LSEL va fi:
FROM Tβ 1
b1,...., Tβ P
bp
Desigur în expresiile de tip 7), 8), 9) şi 10), expresia E1 poate fi o expresie în limbaj
intermediar sau orice expresie logică a limbajului LSEL. În ultimul caz, considerăm TRAN(E1)
= E1. Rezultă că, utilizând expresiile 1) -10), putem construi expresii în Lint şi în acelaşi timp
să obţinem transformarea lor în expresii în LSEL, rezultând în final o frază SELECT
corespunzătoare expresiei Lint.
Exemplul 11. Considerăm tabelele:
a) SECTII cu atributele: CODS (codul secţiei) – cheie unică, DENS – denumirea secţiei,
ETAJ – etajul secţiei respective.
b) PRODUS cu atributele: CODP- codul produsului – cheie unică, DENP – denumire produs,
PRET- preţul unitar al produsului respectiv.
c) FURNIZOR cu CODF- codul furnizorului – cheie unică, NUMEF – nume furnizor,
ADRESAF – adresa furnizorului.
d) FURNIZEAZA cu CODF – codul furnizorului, CODS – codul secţiei în care se face
furnizarea, CODP – codul produsului furnizat, CANT – cantitatea furnizată din produsul
CODP la secţia CODS de către furnizorul CODF.
1) Fie dată interogarea: să se găsească produsele (A.CODP, A.DENP) din PRODUS (aliasul
A) cu proprietatea că A.CODP este furnizat la toate secţiile din tabela SECTII.
E ≡ O(A.CODP, A.DENP) I (PRODUS A) W E1
E1 corespunde la proprietatea A.CODP este furnizat la toate secţiile din tabela SECTII.
E1≡ (∀ B.CODS) [B.CODS ∈ (SECTII B)⇒ E2]
E2 corespunde la faptul că perechea (A.CODP, B.CODS) apare în tabela FURNIZEAZA.
E2 ≡ (A. CODP, B. CODS) τ (FURNIZEAZA C) [C.CODP, C.CODS]
Folosind regulile de transformare definite pentru expresii, obţinem:
(SELECT B. CODS
FROM SECTII B
FROM PRODUS A
WHERE TRAN(E1)
FROM FURNIZEAZA D)
(SELECT C.CODF
FROM FURNIZOR C
(SELECT B.CODS
FROM SECTII B
FROM PRODUS A
WHERE TRAN(E1)
Realizând înlocuirile se obţine comanda SELECT pentru interogarea dată. Desigur, se poate
înlocui subexpresia NOT((c1, c2) IN (SELECT...)) prin (c1, c2) NOT IN (SELECT..) şi NOT
NOT EXISTS (SELECT ...) prin EXISTS (SELECT ...).
3) Fie dată interogarea: să se găsească produsele din PRODUS cu proprietatea că pentru
orice secţie din SECTII, situată la etajul 1, produsul respectiv este furnizat de toţi furnizorii
din FURNIZORI şi produsul respectiv este furnizat de toţi furnizorii din FURNIZORI numai
la secţiile de la etajul 1.
Se remarcă că interogarea are o primă parte ce coincide cu interogarea precedentă, iar partea a
doua trebuie analizată separat.
E ≡ O(A.CODP, A.DENP) I (PRODUS A) W (E1 ∧ E1′ ).
E1 este expresia din interogarea precedentă. Rămîne să exprimăm expresia E1′ . Aceasta
corespunde la interogarea în limbajul Lnat: dacă produsul respectiv (A.CODP) este furnizat de
toţi furnizorii, atunci acest produs este furnizat numai secţiilor de la etajul 1(pentru orice
secţie s cu ETAJ diferit de 1, A.CODP nu îi este furnizat).
E1′ ≡ (∀E.CODF) [E.CODF ∈(FURNIZOR E) ∧ (A.CODP, E.CODF) τ
PRACTICĂ Prof.dr.Victor Felea Pag.32
Asist.drd.Ovidiu Gheorghieş
FURNIZEAZA F [F.CODP, F.CODF]⇒ E′2 ]
E′2 ≡ (∀G.CODS)[G.CODS∈(SECTII G) ∧ (G.ETAJ ≠ 1) ⇒ (A.CODP, G.CODS) NOT
τ FURNIZEAZA H[H.CODP, H.CODS]]
(SELECT G.CODS
FROM SECTII G
WHERE (G.ETAJ<>1)AND
(A.CODP,G.CODS)IN
(SELECT H.CODP, H.CODS
FROM FURNIZEAZA H))
TRAN( E1′ ) ≡ NOT EXISTS
(SELECT E.CODF
FROM FURNIZOR E
FROM FURNIZEAZA F)
FROM PRODUS A
Înlocuind TRAN(E1) din exemplul precedent şi TRAN( E1′ ) calculat mai sus, se obţine
TRAN(E) o interogare SELECT ce realizează interogarea dorită (evident nu este singura
comandă SELECT pentru interogarea dată).
(ii).Să considerăm acum cazul când interogarea în limbaj natural conţine expresii de
grupare pentru calcule de forma minim, maxim, sumă, numărare, medie de valori.
PRACTICĂ Prof.dr.Victor Felea Pag.33
Asist.drd.Ovidiu Gheorghieş
O metodă pentru abordarea unor astfel de interogări va fi utilizarea definirii de tabele
temporare în componenta FROM a comenzii SELECT.
În acest caz componenta FROM a comenzii SELECT are forma:
FROM T1 a1, ..., Th ah
Ti este fie numele unei tabele, fie o expresie de forma (SELECT ...), deci o subselecţie ce
defineşte prin comanda SELECT o tabelă numită tabelă temporară.
O astfel de subselecţie conţine componenta expresiile de ieşire, componenta FROM
(obligatorii) şi poate conţine GROUP BY, HAVING cu expresii funcţii de grupare şi
subselecţii în operandul al doilea al unei expresii din HAVING.
Subinterogarea ce defineşte tabela temporară poate avea un număr oarecare de subselecţii şi
nivele de selecţie.
Rezultă că o comandă SELECT ce are în componenta FROM numai tabele temporare va avea
componentele de ieşire şi componenta FROM de tipul următor:
(SELECT ...) Ah
Subselecţiile din FROM definesc tabele temporare, notate cu T1' ,..., Th' , având aliasurile A1, ...
,Ah, respectiv. Aceste aliasuri sunt obligatorii pentru a face referinţă la câmpurile tabelelor
Tj′, j = 1, h . Din punct de vedere al execuţiei acestei comenzi SELECT, se evaluează întâi
aceste tabele temporare. Evident aliasurile A1, A2,... ,Ah sunt distincte.
Am notat expresia generală în limbajul Lint ce corespunde unei interogări fără GROUP BY şi
HAVING prin:
E≡ O(exp1 c1, ..., expq cq) I(T1 a1, ..., Th ah) W E1,
unde E1 este o expresie în limbajul Lint, construită utilizând expresiile de tip 1) – 10) ale lui
Lint.
În cazul în care, interogarea implică funcţii agregat, atunci vom nota expresia în limbajul Lint
prin:
E≡ O(exp1 c1, ..., expq cq) I(T1 a1, ..., Th ah) W E1 G g1, ..., gs H E 2
unde E1 şi E2 sunt expresii în limbaj intermediar, gi, i = 1,s sunt expresiile de grupare.
Expresiile expj, j = 1, q pot conţine funcţii agregat. Expresia E2 are una din următoarele
forme:
1) E2 ≡ expi θ <constantă>, unde expi este una din expresiile de ieşire ale comenzii, θ
este un operator de comparare, iar <constantă> are tipul lui expi. Semantica lui E2: se reţin
clasele de înregistrări calculate de componenta Gg1, ...,gs care satisfac expresia E2.
2) E2 ≡ COUNT(cimp) θ <constantă>, unde cimp este definit în una din tabelele de
intrare, θ este operator de comparare, <constantă> este de tip numeric. Se calculează E2
pentru fiecare clasă de înregistrări definită de componenta Gg1, ...,gs. Se reţin clasele ce
satisfac expresia E2.
PRACTICĂ Prof.dr.Victor Felea Pag.34
Asist.drd.Ovidiu Gheorghieş
3) E2 ≡ expi θ (E"), unde E" este o expresie în limbajul Lint de forma E" ≡ O(exp')I(T1
b1, ..., Tr br) W E3 G g1′ ,..., g′h H E′2 unde exp' este unica expresie de ieşire a expresiei E" şi
are acelaşi tip cu expi, E3 este expresia din componenta WHERE, g′j , j = 1, t sunt câmpurile
după care se face gruparea, iar E′2 este expresia din componenta HAVING. Simbolul θ este
un operator de comparare.
Expresia E′2 poate utiliza, ca operanzi, expresiile de ieşire expj ale expresiei E.
Pentru 1) şi 2) transformarea lui E2 ca secvenţă a frazei SELECT se realizează prin TRAN(E2)
= E2. Pentru 3) avem: TRAN(E2) ≡ expi θ (TRAN(E")).
Expresia E2 din 3) este adevărată pentru clasa de înregistrări curentă, dacă valoarea lui expi
pentru clasa curentă este în relaţia θ cu valoarea lui exp', calculată de fraza SELECT
corespunzătoare lui E".
4) E2 ≡ <constantă> θ (E"), unde E" se defineşte ca la 3).
Expresia E2 este adevărată pentru clasa curentă, dacă valoarea constantei <constantă>
este în relaţia θ cu exp' calculată de fraza SELECT corespunzătoare lui E". Dacă expresia E 2′
din expresia E" face referiri la expresiile expj, 1≤ j ≤ q de ieşire ale expresiei E, atunci
valoarea exp' din E" depinde de clasele definite de expresia E.
Transformarea ca secvenţă a frazei SELECT va fi:
TRAN(E2) ≡ constantă θ (TRAN(E")).
Observaţie: În cazurile 3) şi 4) TRAN(E2) va avea forma sintactică:
expi θ (SELECT exp' FROM ...), respectiv
constanta θ (SELECT exp' FROM ...)
Atât în expresiile de tipul 1) cât şi în cele de tipul 3), drept prim operand, putem avea o
expresie, ce are ca elemente primare expresiile de ieşire: exp1, ..expq.
De asemenea, drept prim operand poate fi o expresie ce conţine funcţii agregat, expresie ce
corespunde unei clase de înregistrări definită de componenta GROUP BY (G g1, ..., gs) şi care
se evaluează pentru fiecare clasă definită de GROUP BY.
Rezultă că, în cadrul componentei H avem o clasă curentă de considerat, spre deosebire de
componenta W, unde avem un vector curent de înregistrări. Clasele sunt calculate de
componenta G în maniera descrisă în paragraful I.1.
Exemplul 12. Considerăm tabelele SECTII, PRODUS, FURNIZOR, FURNIZEAZA,
VANZARI specificate mai sus.
Se cer produsele (din tabela PRODUS) furnizate la cel puţin o secţie s cu proprietatea că
valoarea totală a vânzărilor realizate în s este mai mare decât o treime din valoarea totală de
vânzare.
Pentru realizarea interogării, putem defini două tabele temporare: T1 ce utilizează funcţia
agregat SUM pentru a calcula valoarea totală a vânzărilor pentru o secţie şi T2 ce calculează
valoarea totală a vânzărilor pentru toate secţiile. Tabela T1 va calcula pentru fiecare s,
valoarea de vânzare realizată la secţia s, iar T2 va calcula valoarea tuturor vânzărilor.
Pentru T1 avem expresia E1:
E1 ≡ O(F.CODSV, SUM(F.CANTV * E.PRET) AS VAL1) I (PRODUS E,
VANZARI F) W (E.CODP = F.CODPV) G F.CODSV
Pentru T2 avem expresia E2:
E2 ≡ O(SUM(H.CANTV * I.PRET) AS VAL2) I (VANZARI H, PRODUS I) W
(H.CODPV = I.CODP)
Interogarea dată va avea expresia E:
E≡ O(C.CODP, C.DENP) I((E1) A, (E2) B, PRODUS C) W α
α ≡ (∃D.CODS) [D.CODS ∈ SECTII D ∧ β ∧ γ]
PRACTICĂ Prof.dr.Victor Felea Pag.35
Asist.drd.Ovidiu Gheorghieş
β ≡ (C.CODP, D.CODS) τ FURNIZEAZA [H.CODP, H.CODS]
γ ≡ (D.CODS = A.CODSV)∧(A.VAL1* 3 > B.VAL2)
Transformările ca secvenţe ale frazei SELECT vor fi:
FROM FURNIZEAZA H)
TRAN(α) ≡ EXISTS
(SELECT D.CODS
FROM SECTII D
WHERE TRAN(α)
SUM(F.CANTV*E.PRET) AS VAL1
FROM PRODUS E, VANZARI F
WHERE (E.CODP =F.CODPV)
GROUP BY F.CODSV
TRAN(E2) ≡ SELECT SUM(H.CANTV*I.PRET) AS VAL2
FROM
GROUP BY F.CODSV) A,
PRODUS C
WHERE EXISTS
(SELECT D.CODS
FROM SECTII D
FROM FURNIZEAZA H)
AND (A.VAL1*3>B.VAL2) )
SUM(E.CANTV*F.PRET) AS VAL1
GROUP BY E.CODSV
SUM(I.CANT*J.PRET) AS VAL2
GROUP BY I.CODS
FROM (TRAN(E1)) A,
(TRAN(E2)) B,
SECTII C
PRACTICĂ Prof.dr.Victor Felea Pag.38
Asist.drd.Ovidiu Gheorghieş
WHERE TRAN(α)
SELECT C.CODS
FROM
GROUP BY E.CODSV) A,
GROUP BY I.CODS) B,
SECTII C
SELECT C.CODS
FROM SECTII C, VANZARI A, PRODUS F
WHERE (C.CODS=A.CODSV) AND (A.CODPV=F.CODP)
GROUP BY C.CODS
HAVING SUM(A.CANTV*F.PRET)*2>
PRACTICĂ Prof.dr.Victor Felea Pag.39
Asist.drd.Ovidiu Gheorghieş
(SELECT SUM(I.CANT*J.PRET)
FROM FURNIZEAZA I, PRODUS J
WHERE (I.CODP=J.CODP) AND
(I.CODS=C.CODS)
GROUP BY I.CODS)
Primul operand al componentei HAVING calculează pentru o secţie C.CODS, dublul valorii
totale vândute de produse în secţia C.CODS.
Al doilea operand al componentei HAVING calculează valoarea totală a produselor furnizate
secţiei C.CODS.
Practică - Modul II
OVIDIU GHEORGHIEŞ
ADRIANA GHEORGHIEŞ
Copyright
c 2002-2007 Ovidiu Gheorghieş, Adriana Gheorghieş
40
Cuprins
1 Introducere 43
4 Modelare 65
4.1 Introducere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.2 Modele. Limbaje de modelare . . . . . . . . . . . . . . . . . . . . 66
41
5 UML 69
5.1 Scurt istoric . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
5.2 Ce este UML? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
5.3 Organizarea modelelor-Pachete . . . . . . . . . . . . . . . . . . . 70
5.4 Diagrama de clase . . . . . . . . . . . . . . . . . . . . . . . . . . 72
5.4.1 Clase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
5.4.2 Relaţii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
5.5 Diagrama de interacţiuni . . . . . . . . . . . . . . . . . . . . . . . 74
5.5.1 Diagrama de secvenţă . . . . . . . . . . . . . . . . . . . . 76
5.5.2 Diagrama de colaborare . . . . . . . . . . . . . . . . . . . 78
6 Modele de proiectare 79
6.1 GRASP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
6.1.1 Information Expert . . . . . . . . . . . . . . . . . . . . . . 80
6.1.2 Creator . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
6.1.3 Low coupling (cuplaj redus) . . . . . . . . . . . . . . . . . 83
6.1.4 High Cohesion (coeziune mare) . . . . . . . . . . . . . . . 84
6.1.5 Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
6.2 Singleton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
6.3 Composite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
6.4 Iterator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
7 Testare 93
7.1 Metode de testare . . . . . . . . . . . . . . . . . . . . . . . . . . 96
7.1.1 Testarea funcţională (Black-box testing) . . . . . . . . . . 96
7.1.2 Testarea stucturală (White-box testing) . . . . . . . . . . 97
7.1.3 Testarea la integrare . . . . . . . . . . . . . . . . . . . . . 98
7.1.4 Testarea interfeţelor . . . . . . . . . . . . . . . . . . . . . 98
7.1.5 Testarea la stress . . . . . . . . . . . . . . . . . . . . . . . 99
7.1.6 Testarea orientată obiect . . . . . . . . . . . . . . . . . . 99
42
Capitolul 1
Introducere
43
reuşim, putem ı̂ncerca a doua zi din nou cu alte lemne şi alte cuie. Iar dacă
câinele refuză să ı̂şi ocupe locuinţa, putem să ı̂l schimbăm cu un altul.
Lucrurile stau radical diferit atunci când dorim să construim o casă pentru
familia noastră. Atunci va trebui sau să angajăm un arhitect care să ne facă un
proiect, sau să cumpărăm un proiect standard de casă. Va trebui să negociem
cu o firmă de construcţii preţul, durata de realizare, calitatea finisajelor. Nu ne
permitem să riscăm economiile familiei pe o construcţie care se va dărâma la
a doua rafală de vânt. În plus, dacă membrilor familiei nu le place orientarea
ferestrelor şi obiectează vehement la faptul că terenul de sport este de baseball
ı̂n loc să fie de tenis, ne va fi greu să ı̂i ı̂nlocuim cu alţii1 .
Cu atât mai mult, cei care ne ı̂ncredinţează câteva milioane de dolari pentru
a ridica un zgârie nori vor fi foarte atenţi cu cine şi ı̂n ce condiţii vor lucra. Ei vor
dori garanţii precum că proiectul este viabil, vor angaja mai multe firme de arhi-
tectură pentru a-l verifica. Deasemenea, studii geologice, de fizică a pamântului,
de meteorologie vor fi obligatorii. Vor fi folosite cele mai performante materiale
şi se vor angaja cei mai competenţi şi cu experienţă constructori. Eşecul nu mai
este o opţiune pentru contractantul proiectului.
Ştim că inginerii constructori ı̂ntocmesc planuri, construiesc machete, stu-
diază proprietăţilor materialelor folosite şi fac rapoarte privind progresul operaţiunilor.
Construcţii de o complexitate foarte mare au fost realizate ı̂n acest fel ı̂ntr-un
mod raţional şi economic. Inginerii de programe ar trebui să procedeze similar
pentru ca dezvoltarea programelor să nu mai fie un proces impredictibil.
Prima definitie dată ingineriei programării a fost enunţată ı̂n anul 1968 astfel:
Ingineria programării este stabilirea şi utilizarea de principii inginereşti so-
lide pentru a obţine ı̂n mod economic programe care sunt sigure şi funcţionează
eficient pe maşini de calcul concrete.
În IEEE Standard Glossary of Software Engineering Tehnology(1983) ingi-
neria programării este definită după cum urmează:
Ingineria programării reprezintă abordarea sistematică a dezvoltării, funcţionării,
ı̂ntreţinerii, şi retragerii din funcţiune a programelor
Remarcăm că a doua definiţie este mai vagă decât prima, ı̂ntrucât nu face
referire la cost şi la eficienţă. Mai mult, se pare că experienţa ı̂n general nega-
tivă acumulată a făcut să se renunţe la formularea “principii inginereşti solide”,
ı̂ntrucât se pare că acestea nu pot fi identificate fără a fi supuse contestaţiilor.
A doua definiţie adaugă ı̂nsă referiri la perioade importante din viaţa unui pro-
gram, ce urmează creării şi funcţionării, anume ı̂ntreţinerea şi retragerea din
functionare.
Considerăm că ingineria programării are următoarele caracteristici impor-
tante:
• Este aplicabilă ı̂n producerea de programe mari
• Este o ştiinţă inginerească
• Scopul final este ı̂ndeplinirea cerinţelor clientului
Programele mici se pot scrie relativ usor, de către un singur programator,
ı̂ntr-o perioadă relativ scurtă de timp. Un program de 100 de instrucţiuni este
cu siguranţă un program mic. Nu putem da o graniţă ı̂ntre un program mic şi
unul mare, ı̂nsă pe măsură ce dimensiunea programului creşte, apar provocări
1 S-ar putea chiar ca ei să fie aceia care să iniţieze procesul de ı̂nlocuire.
44
noi, calitativ diferite. Întrucât un singur sau câţiva programatori nu pot avea
timpul fizic pentru terminarea programului, este necesară crearea a uneia sau
mai multor echipe de lucru. Este necesară coordonarea şi comunicarea ı̂ntre
echipe. Complexitatea sistemului software şi a organizaţiei care realizează siste-
mul software devine netrivială, putând depăşi capacitatea de ı̂ntelegere a unui
singur individ. Apare ca dezirabilă o abordare riguroasă a acestor probleme, ce
include stilul de lucru, modul de scriere a codului, etc. Ingineria programării
propune crearea unor astfel de abordare.
Ingineria programării are ca scop obţinerea de sisteme funcţionale chiar şi
atunci când teoriile şi instrumentele disponibile nu oferă răspuns la toate pro-
vocările ce apar. Inginerii fac lucrurile să meargă, ţinând seama de restricţiile
organizaţiei ı̂n care lucrează şi de constrângerile financiare.
Problema fundamentală a ingineriei programării este ı̂ndeplinirea cerinţelor
clientului [7]. Aceasta trebuie realizată nu punctual, nu ı̂n acest moment, ci
ı̂ntr-un mod flexibil şi pe termen lung. Ingineria programării se ocupă cu toate
etapele dezvoltării programelor, de la extragerea cerinţelor de la client până la
ı̂ntretinerea şi retragerea din folosinţă a produsului livrat. Pe lângă cerinţele
funcţionale, clientul doreşte (de obicei) ca produsul final să fie realizat cu costuri
de producţie cât mai mici. De asemenea, este dezirabil ca aceasta să aibă
performanţa cât mai bună (uneori direct evaluabilă), un cost de ı̂ntreţinere cât
mai mic, să fie livrat la timp, şi să fie sigur.
Prezentăm ı̂n continuare o statistică privind gradul de satisfacere a cerinţelor
pentru proiecte software mari [1]. Aceasta pare să justifice orice disciplină a
muncii care să ı̂mbunătăţească aceste cifre.
• În primii ani ı̂n care calculatoarele au fost introduse la staţiile de benzina
din SUA, consumatorii primeau cecuri pe sume enorme. faptul era privit
ı̂n general cu umor şi reclamaţiile erau rezolvate repede;
45
• Un vehicul de explorare a planetei Venus a fost pierdut deoarece programul
primit de pe Pamânt pentru rectificarea orbitei conţinea linia ’DO 3 I =
1.3’; instrucţiunea corectă ı̂n limbajul FORTRAN ar fi trebuit să conţină
“,” (virgulă) ı̂n loc de “.” (punct);
• În 1979 s-a descoperit o eroare ı̂n programele pentru sistemele de răcire ı̂n
centralele nucleare (SUA); nu fusese niciodată nevoie de executia rutinelor
ce conţineau erorile;
On two occasions I have been asked [by members of Parliament!], “Pray, Mr.
Babbage, if you put into the machine wrong figures, will the right answers
come out?” I am not able rightly to apprehend the kind of confusion of
ideas that could provoke such a question.
— CHARLES BABBAGE
46
Capitolul 2
Modele de dezvoltare a
programelor
• ad hoc (do-it-yourself)
• cascadă (waterfall)
• prototipizare
• metode formale
• spirală
• RUP (Rational Unified Process)
• XP (Extreme Programming)
• analiza cerinţelor
47
• proiectarea arhitecturală
• proiectarea detaliată
• scrierea codului
• integrarea componentelor
• validare
• verificare
• ı̂ntreţinere
Modelul big-bang
În acest model, componentele sunt dezvoltate şi testate individual. Apoi ele
sunt integrate ı̂n sistemul final. Având ı̂n vedere că funcţionarea corectă a
componentelor individuale a fost testată, integrarea ar trebui să fie o formalitate.
Din păcate, componentele nu pot fi testate exhaustiv, iar când acestea lucrează
ı̂mpreună pot să apară situaţii pe care o anumită componentă nu le-a ı̂ntâlnit
ı̂n procesul de testare sau conflicte ı̂ntre anumite componente (de exemplu,
conflicte de partajare a resurselor).
48
S-a constatat că atunci când se aplică acest model, timpul de testare ex-
plodează, proiectul devenind greu de controlat. Aceasta justifică denumirea de
’big-bang’.
Modelul incremental
Acest model propune crearea unui nucleu al aplicaţiei şi integrarea a câte o
componentă la un moment dat, urmată imediat de testarea sistemului obţinut.
Astfel, se poate determina mai uşor unde anume apare o problema ı̂n sistem.
Acest tip de integrare oferă de obicei rezultate mai bune decât modelul big-
bang.
2.1.6 Validare
În procesul de validare ne asigurăm că programul ı̂ndeplineşte cerinţele utiliza-
torului. Întrebarea la care răspundem este: construim produsul corect? 1 .
Un exemplu de validare este testul de acceptare, ı̂n care produsul este pre-
zentat clientului. Clientul spune dacă este mulţumit cu produsul sau dacă mai
trebuie efectuate modificări.
2.1.7 Verificare
În procesul de verificare ne asigurăm că programul este stabil şi că functionează
corect din punctul de vedere al dezvoltatorilor. Întrebarea la care raspundem
este: construim corect produsul? 2 .
2.1.8 Întreţinere
După ce programul este livrat clientului, mai devreme sau mai târziu sunt des-
coperite defecte sau erori ce trebuie reparate. De asemenea, pot apare schimbări
ı̂n specificaţiile utilizatorilor, care vor diverse imbunătăţiri. Întreţinerea constă
ı̂n gestionarea acestor probleme.
• Specificarea cerinţelor
• Proiectarea arhitecturală
• Proiectarea detaliată
• Scrierea codului
• Testarea componentelor
• Testarea sistemului
• Testul de acceptare
1 Are we building the right product? (eng.)
2 Are we building the product right? (eng.)
49
Ingineria
cerintelor
P roiectarea
arhitecturala
P roiectarea
detaliata
Implementare
T estarea
unitatilor
T estarea
sistemului
Acceptare
50
Ingineria
cerintelor
P roiectarea
arhitecturala
P roiectarea
detaliata
Implementare
T estarea
unitatilor
T estarea
sistemului
Acceptare
51
2.4 Prototipizarea
O problemă generală care apare la dezvoltarea unui program este să ne asi-
gurăm că utilizatorul obţine exact ceaa ce vrea. Prototipizarea vine ı̂n sprijinul
rezolvării acestei probleme. Încă din primele faze ale dezvoltării, clientului i se
prezintă o versiune funcţionala a sistemului. Această versiune nu este ı̂ntregul
sistem, ı̂nsă este o parte a sistemului care cel puţin funcţionează.
Prototipul ajută clientul ı̂n a-şi defini mai bine cerinţele şi priorităţile. Prin
intermediul unui prototip el poate ı̂nţelege ce este posibil şi ce nu din punct de
vedere tehnologic. Prototipul, este de obicei produs cât mai repede; pe cale de
consecinţă, stilul de programare este de obicei (cel puţin) neglijent. Însă scopul
principal al prototipului este de a ajuta ı̂n fazele de analiză şi proiectare şi nu
folosirea unui stil elegant.
Se disting două feluri de prototipuri:
• de aruncat (throwaway)
• evoluţionar
În cazul realizării unui prototip de aruncat, scopul este exclusiv obţinerea
unei specificaţii. De aceea nu se acordă nici o importanţă stilului de programare
şi de lucru, punându-se accent pe viteza de dezvoltare. Odată stabilite cerinţele,
codul prototipului este ’aruncat’, sistemul final fiind re-scris de la ı̂nceput, ı̂n
mod tipic chiar ı̂n alt limbaj de programare.
În cazul realizării unui prototip evoluţionar, scopul este de a crea un schelet
al aplicatiei care să poată implementa ı̂n primă fază o parte a cerinţelor siste-
mului. Pe masură ce aplicaţia este dezvoltată, noi caracteristici sunt adaugate
scheletului existent. În contrast cu prototipul de aruncat, aici se investeşte un
efort considerabil ı̂ntr-un design modular şi extensibil, precum şi ı̂n adoptarea
unui stil elegant de programare.
Avantaje:
• permite dezvoltatorilor să elimine lipsa de claritate a specificaţiilor
• oferă utilizatorilor şansa de a schimba specificaţiile ı̂ntr-un mod ce nu
afectează drastic durata de dezvoltare.
• ı̂ntretinerea este redusă, deoarece validarea se face pe parcursul dezvoltării
• se poate facilita instruirea utilizatorilor finali ı̂nainte de terminarea pro-
dusului.
Dezavantaje:
• deoarece prototipul rulează ı̂ntr-un mediu artificial, anumite dezavantaje
ale produsului final pot fi scăpate din vedere de clienţi;
• clientul nu ı̂ntelege de ce produsul necesită timp suplimentar pentru dezvol-
tare, având ı̂n vedere că prototipul a fost realizat atât de repede;
• deoarece au ı̂n fiecare moment şansa de a face acest lucru, clienţii schimbă
foarte des specificaţiile;
• poate fi nepopulară printre dezvoltatori, deoarece implică renunţarea la
propria munca.
52
2.5 Metode formale
În acest model de dezvoltare, sunt folosite formalismul şi rigoarea matematicii.
În prima fază este construită o specificaţie ı̂n limbaj matematic. Apoi, această
specificaţie este transformată ı̂n programe, de obicei ı̂ntr-un proces incremental.
Avantaje:
• precizia obţinută prin specificarea formală;
• păstrarea corectitudinii ı̂n timpul transformării specificaţiei ı̂n cod execu-
tabil;
• oferă posibilitatea generării automate de cod;
• potrivite pentru sisteme cu cerinţe critice.
Dezavantaje:
• specificarea formală este de obicei o barieră de comunicare ı̂ntre client şi
analist;
• necesită personal foarte calificat (deci mai scump);
• folosirea impecabilă a tehnicilor specificării formale nu implică neapărat
obţinerea de programe sigure, deoarece anumite aspecte critice pot fi omise
din specificaţiile iniţiale.
53
1 : pregatirea 2 : gestiunea riscului
[take stock] [dealing with risk]
4 : planif icarea
3 : dezvoltarea
urmatorului stagiu
[development]
[planning]
În modelul spirală (2.3) se consideră că fiecare pas din dezvoltare conţine o
serie de activităţi comune:
• Testare. Se asigură că comportamentele cerute sunt corecte şi că toate
comportamentele necesare sunt prezente ı̂n program.
3 Denumirea ı̂n engleză este, probabil din motive de promovare pe piaţă, ambiguă, putând
54
• Administrarea configuratiei şi a schimbarilor. Se gestionează versiunile
tuturor entităţilor din care este compus programul.
• Administrarea proiectului. Sunt administrate planificările şi resursele.
• Administrarea mediului. Se instalează şi se menţine mediul de lucru ne-
cesar dezvoltării programului.
• Plasament. Se efectuează activităţile necesare punerii ı̂n funcţiune a pro-
gramului.
2.7.1 Pornire
În faza de pornire, scopul principal al iteraţiilor este să ajute echipa de dezvoltare
să stabileasca care vor fi obiectivele esenţiale ale proiectului. Se vor explora
arhitecturi alternative şi soluţii tehnice posibile.
În urma acestei activităţi, se obţin următoarele:
• o enumerare a cerinţelor principale, posibil ı̂n formă de cazuri de utilizare;
• o imagine de ansamblu asupra arhitecturii programului;
• o descriere a obiectivelor proiectului;
• un plan preliminar de dezvoltare.
55
Figura 2.4: Activităţile ı̂n cadrul RUP
56
2.7.2 Rafinare
În faza de rafinare se stabileşte o ı̂ntelegere detaliată a problemei care trebuie
rezolvată, se hotărăşte arhitectura programului, se stabileşte echipa de lucru, se
elimină situaţiile cu risc mare.
Această activitate produce următoarele:
2.7.3 Construire
Iteraţiile din faza de contruire au ca rol adăugarea se diverse caracteristici pro-
gramului dezvoltat. În această fază se aşteaptă ca cazurile de utilizare oferite
de client să se stabilizeze ı̂n mare masură, deşi ı̂n unele aplicaţii este posibil ca
ele să sufere oarecari modificări.
Cazurile de utilizare sunt adaugate unul câte unul, iteraţie cu iteraţie la
program, până când clienţii pot utiliza programul ı̂ntr-un mod apropiat de cel
aşteptat.
Activitatea de construire produce următoarele:
• Programul propriu-zis
• Teste
• Manuale de utilizare
2.7.4 Tranzitie
În cadrul acestei activităti programul este ı̂mbogaţit mai departe cu caracteris-
tici, ı̂nsă accentul se pune pe ı̂mbunătăţirea şi rafinarea celor existente.
Sfârşitul acestei activitati şi a ı̂ntregului proces de dezvoltare are loc atunci
când:
De remarcat că a doua situaţie nu se suprapune peste prima. Adesea pot să
apară cerinţe ce nu au fost propuse iniţial.
57
XP consideră că dezvoltarea programelor nu ı̂nseamna ierahii, responsabi-
lităţi şi termene limită aşa cum se află acestea pe masa administratorului, ci
ı̂nseamnă colaborarea oamenilor din care este formată echipa. Aceştia sunt
ı̂ncurajati să ı̂şi afirme personalitatea, să ofere şi să primească cunoaştere şi să
devină programatori străluciti.
Deasemenea, XP consideră că dezvoltarea de programe ı̂nseamnă ı̂n primul
rând scrierea de programe. Această sintagmă banală se pare că este uitată de
multe companii care se ascund ı̂n spatele proceselor de dezvoltare stufoase, a
sedinţelor şi a rapoartelor de activitate. XP ne aminteşte cu respect ca fişierele
PowerPoint nu se pot compila.
De altfel, inspirarea proceselor de dezvoltare a programelor din ingineria
construcţiilor se pare că nu este cea mai fericită alegere. Este adevarat că un
inginer care vrea să construiască un pod peste un râu face intâi măsuratori,
realizează un proiect şi abia apoi trece la executie, toate acestea ı̂ntr-un mod
secvential şi previzibil. Dar dezvoltarea de programe nu seamănă cu aşa ceva,
oricât am vrea să ne păcălim să credem asta. Dacă inginerului constructor
respectiv i s-ar schimba cerinţele de rezistentă, i s-ar muta malurile şi i s-ar
schimba râul din Siret ı̂n Amazon, pentru frumusete chiar când a terminat de
construit jumătate de pod, putem fi siguri că acel inginer şi-ar schimba modul
de lucru. Din pacate ı̂nsa, nu stim (ı̂ncă) cum.
Iniţiatorii XP, Jon Jeffries şi Kent Beck definesc următoarele două carte, ca
bază filozofică pentru această metodologie.
• Ai dreptul să ştii ceea ce se cere, prin cerinţe clare, cu declaraţii clare de
prioritate.
• Ai dreptul să spui cât ı̂ţi va lua să implementezi fiecare cerinţă, şi să ı̂ţi
revizuieşti estimările ı̂n funcţie de experienţă.
• Ai dreptul să ı̂ţi accepţi responsabilităţile, ı̂n loc ca acestea să-ţi fie asig-
nate.
• Ai dreptul la un plan general, să ştii ce poate fi făcut, când, şi la ce preţ.
• Ai dreptul să vezi progresul ı̂ntr-un sistem care rulează şi care se dovedeste
că funcţionează trecând teste repetabile pe care tu le specifici.
58
Aceste afirmaţii, deşi par ı̂ntelese de la sine, conţin semnificaţii profunde.
Multe din problemele apărute ı̂n dezvoltarea programelor pornesc de la ı̂ncalcarea
acestor principii.
Enumerăm pe scurt câteva dintre caracteristicile XP.
• Proiectul este ı̂n mintea tuturor programatorilor din echipa, nu ı̂n documentaţii,
modele sau rapoarte.
• Dacă apare necesitatea rescrierii sau aruncării de cod, aceasta se face fără
milă.
• Modificarile aduse codului sunt integrate continuu (de cateva ori pe zi).
Nu vom discuta aici avantajele aduse de această abordare şi nici criticile care
ı̂i sunt adresate. Le lăsăm ca subiecte de meditaţie pentru cititor.
It took 300 years to build and by the time it was 10% built,
everyone knew it would be a total disaster. But by then the investment
was so big they felt compelled to go on. Since its completion, it has
cost a fortune to maintain and is still in danger of collapsing.
There are at present no plans to replace it, since it was never
really needed in the first place.
— K.E. IVERSON, despre turnul din Pisa
59
60
Capitolul 3
61
• o abstractizare a unui obiect
• un tip de date
Spunem că un obiect care aparţine unei clase este instanţă a acelei clase.
• ı̂ncapsularea
• moştenirea
• polimorfismul
În principiu, orice limbaj de programare orientat obiect ar trebui să ofere
suport pentru construcţiile de mai sus. Astfel, ar fi posibil să transpunem o
arhitectură orientată obiect ı̂n orice limbaj orientat obiect disponibil.
Toate aceste trei caracteristici promovează reutilizarea codului. Încapsularea
permite ca o clasă să fie folosită fără a şti cum functionează (modularitate, abs-
tractizare). Moştenirea permite reutilizarea codului prin folosirea de caracteris-
tici deja existente şi adaugarea de altele noi. Polimorfismul permite scrierea unei
clase generale care specifică o interfaţă a carei implementare va fi specificată şi
apelată ı̂ntr-un mod transparent pentru clasele care o moştenesc.
3.2.1 Încapsulare
Încapsulare ı̂nseamna punerea ı̂mpreuna a părţilor puternic corelate ale unui
program ı̂n scopul creării de unităţi ce pot fi proiectate, implementate, depanate,
testate şi menţinute una căte una.
Limbajele orientate obiect consideră codul şi datele ca parte a unei entităţi
indivizibile numite obiect. Datele conţinute ı̂ntr-un obiect sunt de regulă mo-
dificate doar prin intermediul codului (metodelor) obiectului respectiv. Fiecare
obiect poate fi privit ca un mic procesor a cărui comportare este definită de
modul cum răspunde la un apel de metodă.
Într-un sistem orientat obiect se lucrează ı̂n mod uzual cu o colectie de
obiecte ce cooperează pentru a obţine un anumit rezultat.
Ascunderea informaţiei: utilizatorii unui obiect nu au nevoie să stie (nu-i
interesează, nu trebuie să stie) implementarea metodelor. Un utilizator poate
modifica starea obiectului doar ı̂n mod indirect, prin apelul de metode. El nu
trebuie să ştie modalitatea ı̂n care modifică metoda starea obiectului ci doar
efectul acestei modificari. Un avantaj al acestei abordări este că ı̂mbunătăţiri
ale codului pot apare fără a schimba interfaţa. Această separare este esenţială
pentru producerea de cod refolosibil şi usor de intreţinut.
62
3.2.2 Mostenirea
Adesea anumite clase sunt percepute ca specilizări ale altor clase.
De exemplu:
Mai spunem că sub-clasa sau clasa derivată moşteneşte caracteristicile super-
clasei.
Avantaje:
• Definiţii concise ale claselor: pentru subclase este suficient să descriem
cum diferă faţă de super-clase.
• Reutilizarea codului: ı̂n loc să duplice codul, clasele derivate reutilizează
codul existent ı̂n superclasă.
3.2.3 Polimorfismul
Polimorfism: interpretarea semanticii unui apel de metodă se face de catre cel
care primeste apelul, nu de catre apelant (acelasi apel de metoda se poate com-
porta diferit pentru tipuri de obiecte diferite).
Extinderea programelor cu tipuri noi de date se simplifică foarte mult.
Informaţii suplimentare: [6].
63
64
Capitolul 4
Modelare
4.1 Introducere
Problema principală care apare ı̂n dezvoltarea programelor este complexitatea.
Folosirea de modele poate ı̂nlesni abordarea de probleme complexe. Un model
este o simplificare unui anumit sistem, ce permite analizarea unora dintre pro-
prietăţile acestuia. Lucrul cu modelele poate facilita o mai bună ı̂nţelegere a
sistemului modelat, datorită dificultăţii intrinseci de ı̂ntelegere a sistemului ı̂n
ı̂ntregul sau. Folosirea tehnicii “divide et impera” permite ı̂nţelegerea părţilor
componente ale unui sistem, iar ansambul sistemului ca o interacţiune ı̂ntre
părţile acestuia. Un model reuşit reţine caracteristicile importante ale obiectului
modelat şi le ignoră pe cele irelevante. De remarcat că noţiunile de importan-
t/irelevant sunt relative, ele depinzând de scopul pentru care se face modelarea.
Astfel apare plauzibilă construirea mai multor modele pentru un anumit obiect,
fiecare surprinzănd anumite aspecte ale acestuia.
Orice metodologie de dezvoltare a programelor abordează problema comu-
nicării ı̂ntre membrii echipei. Este posibil să apară situaţii ı̂n care modelul
construit de proiectant să nu fie ı̂nteles exact de cel ce scrie cod, fie din cauza
lipsei de precizie a modului ı̂n care este prezentat modelul, fie datorită incom-
pletitudinii acestuia; adesea o serie de amănunte subtile ce sunt evidente pentru
designer nu sunt transmise. O rezolvare a problemei comunicarii ar fi ca aceeaşi
persoană să fie implicată direct ı̂n toate fazele dezvoltării. Chiar şi aşa, apare
des situaţia ı̂n care o persoană trebuie să continuie munca alteia. Se impune
aşadar existenţa unui limbaj formal de comunicare al cerinţelor.
Termenul formal este esenţial. De obicei, chiar şi ı̂n proiecte de dimensiuni
reduse, se face modelare, ı̂nsă ı̂ntr-un limbaj specific celui care modelează, deter-
minat viziunea sa asupra problemei şi de pregatirea acestuia (un matematician
va utiliza o notatie algebrică, un arhitect o notatie preponderent grafică etc.)
Folosirea unui limbaj “intern” nu trebuie privită ca negativă, ea având se pare
un rol esenţial ı̂n gândire ı̂n general şi ı̂n modelare ı̂n particular. Modelarea este
posibilă, chiar şi fără folosirea explicită a unui limbaj:
Cuvintele scrise sau limbajul rostit, nu par să joace nici un rol ı̂n meca-
nismele gândirii mele. Entităţile fizice ce par să servească drept elemente de
gândire sunt anumite semne şi imagini mai mult sau mai puţin clare ce pot fi
reproduse şi combinate “voluntar”. (Albert Einstein)
65
Aceasta nu ı̂nseamnă că a comunica altora ideile este facil:
Trebuie să traduc gândurile ı̂ntr-un limbaj ce nu curge la fel de lin. Aşa
că pierd o groază de timp cautănd cuvintele şi frazele corespunzătoare, şi sunt
conştient că atunci cănd mi se cere brusc să vorbesc, de multe ori sunt foarte
neclar datorită faptului că mă exprim pur şi simplu stăngaci şi aceasta nu din
cauza lipsei de claritate a percepţiei. (Francis Galton)
Aşa cum formalismul raţionamentului matematic poate fi agentul de trans-
misie al adevarului matematic [5] (care, odată transmis, este “tradus” ı̂n lim-
bajul intern al receptorului), formalismul limbajului de modelare constă din
stabilirea de elemente cu o semantică asupra căreia se convine şi cu ajutorul
cărora să se poată trasmite idei ı̂n mod cât mai eficient şi neambiguu.
Limbajul de modelare UML ı̂şi propune să definească o modalitate cât mai
precisă, generală şi extensibilă de comunicare a modelelor. El a fost creat ı̂n pri-
mul rând pentru a facilita proiectarea programelor, ı̂nsa datorită expresivitâţii
sale poate fi folosit şi ı̂n alte domenii (proiectare hardware, modelarea proceselor
de afaceri etc.) [4]
Folosirea UML facilitează comunicarea modelelor, ı̂nsă nu asigură crearea
unui model bun. Limbajul de modelare nu specifică şi nu poate specifica ce
modele trebuie create, ı̂n ce ordine ŝi cum trebuie ele utilizate pentru un sistem
particular. El nu este un ı̂nlocuitor al inteligentei, experienţei şi bunului gust
[8].
66
v
m
67
68
Capitolul 5
UML
69
Systemhouse, Microsoft, Oracle, Rational, Texas Instruments etc. UML 1.0 a
fost propus spre standardizare ı̂n cadrul OMG ı̂n ianuarie 1997.
Până la sfârşitul anului 1997 echipa care lucra la UML s-a extins, urmând o
perioadă ı̂n care UML a primit o specificare formală mai riguroasă. Versiunea
UML 1.1 a fost adoptată ca standard de catre OMG ı̂n noiembrie 1997. Actual-
mente UML este dezvoltat de catre OMG Revision Task Force, condus de Cris
Kobryn. Versiunea 1.2 a UML a fost o revizie editoriala; versiunile 1.3 au fost
publicate ı̂ncepând cu sfârşitul anului 1998. În septembrie 2001 a fost publicată
versiunea 1.4. În momentul de faţă se lucrează la versiunea 2.0 a UML.
• Diagrame de implementare:
70
Figura 5.1: Notaţia grafică pentru pachet
71
Figura 5.3: Exemplu de notaţie grafică pentru clasă
5.4.1 Clase
Elementele unei clase sunt: Nume - prin care se distinge de alte clase. O clasă
poate fi desenată arătându-i numai numele.
Atribute - un atribut reprezintă numele unei proprietăţi a clasei.
Operaţii (metode) - o operatie reprezintă implementarea unui serviciu care
poate fi cerut oricărui obiect al clasei.
O clasă poate avea oricâte atribute şi operaţii sau poate să nu aibă nici un
atribut sau nici o operaţie. Modelarea vocabularului unui sistem presupune
identificarea elementelor pe care utilizatorul sau programatorul le foloseşte pen-
tru a descrie soluţia problemei. Pentru fiecare element se identifică o mulţime
de responsabilităţi (ce trebuie să facă acesta), dupa care se definesc atributele
şi operaţiile necesare ı̂ndeplinirii acestor responsabilităţi.
5.4.2 Relaţii
O relatie modelează o conexiune semantică sau o interacţiune ı̂ntre elementele
pe care le conectează. În modelarea orientată obiect cele mai importante relaţii
72
Figura 5.4: Notaţiile grafice pentru diferite tipuri de relaţii (a) asociere
bidirecţională, (b) asociere unidirecţională, (c) agregare, (d) dependenţă, (e)
generalizare, (f) realizare
Relaţia de asociere
Asocierea este o relaţie importantă ce apare foarte des ı̂n diferite contexte de
modelare. Ea se foloseşte pentru a exprima o conexiune semantica ı̂ntre obiecte
individuale aparţinând unor anumite clase.
Asocierile poartă informaţii despre legăturile dintre obiectele unui sistem. Pe
masură ce sistemul evoluează, legăturile dintre obiecte pot fi create sau distruse.
Relaţia de asociere oferă baza arhitecturală pentru modelarea conlucrării şi
interacţiunii dintre clase.
O asociere interacţionează cu obiectele sale prin intermediul capetelor de
asociere. Capetele de asociere pot avea nume, cunoscute sub denumirea de ro-
luri, şi vizibilitate, ce specifică modul ı̂n care se poate naviga ı̂nspre respectivul
capăt de asociere. Cea mai importantă caracteristică a lor este multiplicitatea,
ce specifică câte instanţe ale ale unei clase pot fi relaţionate cu o instanţă a altei
clase. De obicei multiplicitatea este folosită pentru asociaţiile binare.
Reprezentarea grafică a asocierii este o linie (sau drum) ce conectează clasele
ce participă ı̂n asociere. Numele asocierii este plasat pe linie, iar multiplicitatea
şi rolurile sunt plasate la extremităţile sale (figura 5.5).
Este posibilă specificarea direcţiei unei asocieri, pentru a elimina legături
redundante sau irelevante pentru un anumit model. În această situaţie notaţia
grafică pentru relaţia de asociere este o linie cu o săgeată la unul din capete
73
indicând direcţia asocierii (figura 5.4 (b)).
Relaţia de agregare
O agregare este o asociere ce modelează o relaţie parte-ı̂ntreg. Este reprezentată
ca un romb gol ataşat la capătul asocierii de lângă clasa agregat (figura 5.4 (c)).
În figură o instanţă a clasei A conţine o instanţă a clasei B (altfel spus un obiect
B este o parte unui obiect A).
Relaţia de agregare este deci un caz particular al relaţiei de asociere. Ea
poate avea toate elementele unei relaţii de asociere, ı̂nsă ı̂n general se specifică
numai multiplicitatea. Se foloseşte pentru a modela situaţiile ı̂n care un obiect
este format din mai multe componente.
Relaţia de dependenţă
O dependenţă (figura 5.4 (d)) indică o relaţie semantică ı̂ntre două elemente ale
modelului. Se foloseşte ı̂n situaţia ı̂n care o schimbare ı̂n elementul destinaţie
(B) poate atrage după sine o schimbare ı̂n elementul sursă (A). Această relaţie
modelează interdependenţelor ce apar la implementare. Dependenţele pot să
apară şi la structurarea unui sistem ı̂n pachete, definind arhitectura sistemului.
Relaţia de generalizare
Relaţia de generalizare (figura 5.4 (e)) se foloseşte pentru a modela conceptul
de moştenire ı̂ntre clase. În figură clasa A este derivată din clasa B. Spunem
că A este clasa derivată (sau subclasa, sau clasa copil), iar B este clasa de baza
(sau superclasa, sau clasa părinte).
Relaţia de generalizare mai poartă denumirea de relaţie de tip is a (este un
fel de), ı̂n sensul că o instanţă a clasei derivate A este ı̂n acelaşi timp o instanţă
a clasei de bază B (clasa A este un caz particular al clasei B sau, altfel spus,
clasa B este o generalizare a clasei A). Clasa A moşteneşte toate atributele şi
metodele clasei B. Ea poate adăuga noi atribute sau metode sau le poate redefini
pe cele existente.
Relaţia de realizare
Relaţia de realizare (figura 5.4 (f)) se foloseşte ı̂n cazul ı̂n care o clasă (A)
implementează o interfaţă (B). Se spune că A realizează interfaţa specificată de
B. O interfaţă este o specificare comportamentală fără o implementare asociată.
O clasă include o implementare. Una sau mai multe clase pot realiza o interfaţă
prin implementarea metodelor definite de acea interfaţă.
Figura 5.6 prezintă un exemplu de diagramă de clase.
74
Figura 5.6: Exemplu de diagramă de clase.
75
• o operaţie: interacţiuni ı̂ntre parametri, variabile locale şi globale
Scopul unei diagrame de interacţiuni este acela de a specifica modul ı̂n care
se realizează o operaţie sau un caz de utilizare.
Obiectele care participă la o interacţiune pot fi lucruri concrete sau pro-
totipuri. De obicei, ı̂ntr-o colaborare obiectele reprezintă prototipuri ce joaca
diferite roluri, şi nu obiecte specifice din lumea reală.
Între obiectele care participă la o colaborare se pot stabili legături. O
legătură (link) reprezintă o conexiune semantică ı̂ntre obiecte. Ea este o instanţă
a unei asocieri şi poate avea toate atributele specifice asocierii (nume, roluri, na-
vigare, agregare), dar nu şi multiplicitate.
Obiectele care interactionează comunica ı̂ntre ele, comunicarea facându-se
prin schimb de mesaje. Un mesaj specifică o comunicare ı̂ntre obiecte. El
poartă o informatie şi este urmat de o activitate.
Primirea unei instante a unui mesaj poate fi considerată o instanţă a unui
eveniment. Unui mesaj ı̂i este asociată o acţiune care poate avea ca efect schim-
barea stării actuale a obiectului.
Tipuri de acţiuni existente ı̂n UML:
• call: invocă o operaţie a unui obiect. Un obiect ı̂şi poate trimite lui ı̂nsuşi
un mesaj (invocare locală a unei operaţii). Este cel mai comun tip de
mesaj. Operaţia apelată trebuie să fie definită de obiectul apelat şi vizibilă
apelantului.
76
Figura 5.7: Exemplu de diagramă de secvenţă care ilustrează ce se ı̂ntâmplă
atunci când un student propune un proiect
77
5.5.2 Diagrama de colaborare
Diagrama de colaborare: pune accentul pe organizarea structurală a obiectelor
care participă la interacţiune. Ea conţine obiecte, legături care se stabilesc
ı̂ntre acestea, precum şi mesajele prin care obiectele comunică. Mesajele sunt
prefixate de un număr care indică ordonarea ı̂n timp a acestora şi sunt ataşate
legăturilor dintre obiecte. Unei legături ı̂i pot fi ataşate mai multe mesaje.
Notaţia grafică: este un graf ı̂n care vârfurile reprezintă obiecte, iar arcele
reprezintă legaturile dintre ele.
78
Capitolul 6
Modele de proiectare
6.1 GRASP
Acronimul GRASP vine de la General Responsibility Assignement Software Pat-
terns (modele generale de asignare a responsabilitatilor in software). Descrise de
Craig Larman ı̂n cartea Applying UML and Patterns. An Introduction to Object
Oriented Analysis and Design, scopul lor este sa ne ajute să alocăm responsabi-
lităţi claselor ı̂n cel mai elegant mod posibil. Modelele sunt numite: Information
Expert (sau Expert), Creator, High Cohesion, Low Couplig şi Controller. In cele
79
ce urmeaza le vom descrie pornind de la problema pe care fiecare isi propune sa
o rezolve.
Sale
-date
-time
1
Contains
1..*
ProductSpecification
SalesLineItem * Described by 1
-description
-quantity
-price
-itemId
80
Continuam procesul de analiza. Ce informatii sunt necesare pentru a de-
termina subtotalul pentru o instanta a clasei SalesLineItem? Avem nevoie sa
cunoastem cantitatea de produs care este vanduta, precum si pretul produsu-
lui. SalesLineItem cunoaste cantitatea si produsul asociat (instanta a clasei
ProductSpecification, deci SalesLineItem poate sa determine subtotalul.
In termeni de diagrama de interactiuni, acest lucru inseamna ca Sale tre-
buie sa trimita mesaje de tipul getSubtotal fiecarei instante SalesLineItem pe
care o contine si sa faca suma rezultatelor. Acest design este ilustrat in figura
urmatoare:
1.1: p:=getPrice()
:ProductSpecification
81
Sale
-date
-time
+getTotal()
Contains
1..*
ProductSpecification
SalesLineItem Described by 1
* -description
-quantity
-price
+getSubtotal()
-itemId
+getPrice()
6.1.2 Creator
Problemă: cine trebie să fie responsabil cu crearea unei instanţe a unei clase?
Soluţia propusa de Creator este sa-i fie asignata clasei B responsabilitatea de
a crea instanţe ale clasei A doar dacă cel puţin una dintre următoarele afirmaţii
este adevărată:
82
Sale
-date
-time
1
Contains
1..*
ProductSpecification
SalesLineItem * Described by 1
-description
-quantity
-price
-itemId
:Register :Sale
addLineItem(itemType, quantity)
create(itemType, quantity)
:SalesLineItem
83
Forme comune de cuplaj de la o clasa A la o clasa B sunt:
2:addPayment(p)
:Sale
(a)
makePayment() 1:makePayment()
:Register :Sale
1.1:create()
(b) :Payment
In figura (a) există legături ı̂ntre toate clasele, pe când ı̂n figura (b) este
eliminat cuplajul dintre Register şi Payment.
• dificultate de ı̂nţelegere
• greu de refolosit
• intretinere greoaie
Coeziunea şi cuplajul sunt principii vechi ı̂n proiectarea software. Ambele
promovează un design modular. Modularitatea este proprietatea unui sistem
care a fost descompus ı̂ntr-o mulţime de module coezive şi slab cuplate.
84
6.1.5 Controller
Problemă: Cine este responsabil cu tratarea unui eveniment generat de un
actor? Aceste evenimente sunt asociate cu operaţii ale sistemului.
Un Controller este un obiect care nu ţine de interfaţa grafică şi care este
responsabil cu recepţionarea sau gestionarea unui eveniment. Pentru fiecare
operaţie a sistemului controlerul defineşte o metoda corespunzătoare.
Soluţia propusă de acest model de proiectare este de a asigna responsa-
bilitatea pentru recepţionarea sau gestionarea unui eveniment unei clase care
reprezintă una dintre următoarele alegeri:
• Reprezintă ı̂ntregul sistem sau subsistem (façade controller)
• Reprezintă un scenariu de utilizare ı̂n care apare evenimentul; deseori
acesta este numit [UseCaseName]Handler, [UseCaseName]Coordinator
sau [UseCaseName]Session (use-case or session controller). Informal,
o sesiune reprezintă o instanţă a unei conversaţii cu un actor. Sesiunile
pot avea orice lungime, ı̂nsă sunt organizate, de obicei, ı̂n termeni de sce-
narii. Se recomandă folosirea unei singure clase Controller pentru toate
evenimentele care apar ı̂n acelaşi scenariu de utilizare.
În mod normal, un controller ar trebui sa delege altor obiecte munca ce tre-
buie făcută. Controller-ul coordonează sau controlează activitatea, ı̂nsă nu face
prea multe lucruri el ı̂nsuşi. O greşeală comună ı̂n proiectarea unui controller
este să i se atribuie prea multe responsabilităţi (mai ales in cazul unui façade
controller). Un UseCaseController este o alegere bună ı̂n cazul ı̂n care există
multe evenimente care apar ı̂n procese diferite. În această situaţie se recomandă
o ı̂mpărţire a responsabilităţilor ı̂n mai multe clase. Soluţia obţinută ı̂n acest
fel este mai uşor de gestionat şi, ı̂n plus, oferă o bază pentru a putea determina
starea scenariului aflat ı̂n desfăşurare.
6.2 Singleton
Uneori intr-o apliactie este nevoie de un obiect global care sa poata fi accesat de
oriunde, insa care trebuie creat o singura data. Vrem ca toate modulele aplicatiei
sa poata folosi obiectul, insa toate trebuie sa foloseasca aceeasi instanta.
De exemplu, am putea dori ca ı̂ntr-o aplicaţie să avem definit un singur
gestionar de securitate care sa se ocupe de drepturile de acces ale utilizatorilor
la diferite parti ale aplicatiei sau un singur gestionar de conexiuni la baza de
date, iar intr-un sistem ar trebui sa avem o singura coda de imprimare pentru
fiecare imprimanta disponibila.
O modalitate de a realiza acest lucru ar fi sa cream un obiect global, iar
apoi sa transmitem o referinta la acest obiect tuturor obiectelor care ar putea
avea nevoie de el. Totusi, este dificil sa ne dam seama cum vrem sa transmitem
referinta si sa stim de la inceput ce parti ale aplicatiei au nevoie sa foloseasca
obiectul. Un alt dezavantaj al acestei abordari este acela ca nu impiedica un alt
obiect sa creeze o alta instanta a obiectului global.
O alta abordare posibila pentru a putea avea valori globale ar fi sa folosim
variabile statice. Aplicatia poate avea cateva obiecte statice in interiorul unei
clase si le poate accesa in mod direct. Exista, insa, si in acest caz dezavantaje.
Obiectele statice se creeaza la momentul incarcarii unei clase, deci nu avem
85
nici o modalitate de a le furniza date de initializare inainte de instantiere. Mai
mult, nu putem controla cine acceseaza obiectul si cum este acesta modificat, o
instanta statica fiind disponibila public oricui.
In aceste situatii modelul de proiectare Singleton devine util. Un singleton
(sau unicat) este o clasă ce poate avea o singură instanţă. Singletonul este
util atunci când se doreşte garantarea faptului că o anumită resursă există ı̂n
aplicaţie ı̂ntr-o singură copie şi că toate componentele pot folosi doar acea copie.
Secvenţa de cod de mai jos arată cum ar putea fi folosit un unicat:
Singleton
static uniqueInstance: return uniqueInstance
singletonData
static GetInstance()
Operation()
GetSingletonData()
private Singleton() {
//initialization code here;
}
86
public void Operation() {
}
6.3 Composite
Un compozit se foloseşte pentru a reprezenta relaţii de tip parte-intreg ı̂ntre
obiecte, cu posibilitatea de a grupa obiectele ı̂n structuri arborescente. Obiectele
şi grupurile de obiecte sunt tratate uniform.
De exemplu, să considerăm o aplicaţie de editare grafică care lucrează cu cer-
curi, triunghiuri si pătrate. În această aplicaţie este posibil ca anumite obiecte
selectate să fie grupate. Atunci când se acţionează asupra unui astfel de grup,
se acţionează asupra tuturor obiectelor din grup: dacă se translatează grupul,
atunci fiecare obiect ı̂n parte este translatat. Mai mult este posibil să se creeze
grupuri care să conţină atât obiecte atomice, cât şi alte grupuri create anterior.
Astfel, grupurile de obiecte pot fi tratate ca şi cum ar fi obiecte individuale.
Diagrama de clase pentru un compozit este prezentată mai jos.
Component
Client Operation()
Add(c:Component) child
Remove(c:Component)
GetChild(i:int)
În cazul nostru, o metodă de tip Operation ar putea fi Move, care realizează
deplasarea obiectului. Compozitul ar implementa metoda Move astfel:
87
void Composite::Move(double dx, double dy)
{
for(Iterator it = GetChildrenIterator(); it.hasNext(); it.next()) {
Component child = it.hasItem();
child.Move(dx, dy);
}
}
Un exemplu de cod Java care implementeaza diagrama de mai sus este pre-
zentat in cele ce urmeaza:
88
}
6.4 Iterator
Un iterator oferă posibilitatea de a accesa ı̂n mod secvenţial obiectele agregate
ı̂ntr-un alt obiect, fără a cunoaşte modul de agregare.
In mod tipic, un iterator it este folosit astfel:
for(it.First();!it.IsDone();it.Next()) {
Item item = it.CurrentItem();
// use item
}
Acest cod poate fi scris si utilizat fara probleme. Daca insa la un moment
vom dori, intr-un mod eficient, sa adaugam in structura de date noi inregistrari,
sau sa stergem inregistrari existente, va trebui sa ne gandim la o alta structura
de date, de exemplu la o lista inlantuita. Lista inlantuita va rezolva problemele
de mai sus, insa ne va obliga sa modificam codul de parcurgere la:
89
Iteratorii sunt utili şi din alt punct de vedere. La un moment dat ı̂ntr-un
program pot fi folosite containere de mai multe tipuri, fiecare folosind modali-
tatea sa specifica de a agrega elemente. Desigur, pentru fiecare tip de container
trebuie implementat un iterator specific, care să implementeze modul de iterare
printre elemente. Ceea ce trebuie remarcat este că, oricare ar fi un iterator
concret, codul de utilizare este identic. Astfel, apare ca utilă ideea de a crea o
interfaţă pentru toţi iteratorii, şi de a se folosi acea (unică) interfaţă pentru a
enumera elementele containerelor.
Astfel, codul următor:
void process(Iterator& it)
{
for(it.First();!it.IsDone();it.Next()) {
Item item = it.CurrentItem();
// use item
}
}
poat fi apelat şi pentru iteratori peste vectori şi pentru iteratori peste liste:
In general, schema unui iterator este urmatoarea:
Client
Iterator
Aggregate
First
CreateIterator() Next()
IsDone()
CurrentItem()
ConcreteAggregate ConcreteIterator
CreateIterator()
return new
ConcreteIterator(this)
90
public interface Aggregate {
Iterator createIterator();
}
91
if( index < aggregate.storage.size() ) {
object = aggregate.storage.elementAt( index ); } else {
throw new IndexOutOfBoundsException();
}
return object;
}
}//class
92
Capitolul 7
Testare
93
T estarea
unitatilor
T estarea
modulelor
T estarea
subsistemelor
T estarea
sistemului
T estul
de acceptare
94
Localizeaza P roiecteaza modalitatea Corecteaza Retesteaza
eroarea de corectare a erorii eroarea programul
activitate scoate deseori ı̂n evidenţă defecte ale programului care trebuie elimi-
nate. Procesul care se ocupă cu localizarea şi corectarea erorilor din program
poartă denumirea de debugging. Figura 7.2 ilustrează un posibil proces de de-
bug. Defectele ı̂n codul sursă trebuie localizate, iar programul trebuie să fie
modificat pentru a satisface cerinţele. Testarea trebuie repetată pentru a avea
siguranţa că modificările făcute sunt corecte. Deci procesul de debug este o
parte atât dezvoltării cât şi a testării unui program. Testarea unităţilor este,
prin urmare, o parte a procesului de implementare. Ca rezultat al etapei de tes-
tare a unităţilor sunt aşteptate componente conforme cu specificaţiile pe baza
cărora au fost dezvoltate.
Etapele următoare presupun integrarea muncii mai multor programatori.
Ele trebuie planificate şi o echipă trebuie să lucreze pe un plan de testare dezvol-
tat pe baza specificaţiilor şi a designului sistemului. Figura 7.3 ilustrează modul
ı̂n care planurile de test sunt legate de activităţile de testare şi dezvoltare.
Testarea ı̂n vederea acceptării mai poartă denumirea de testare alpha (al-
pha testing). În această situaţie sistemele sunt dezvoltate pentru un singur
client. Procesul de testare alpha continuă până când clientul şi dezvoltatorul
cad de acord asupra faptului că sistemul oferit este o implementare acceptabilă
a cerinţelor clientului.
Când sistemul va fi vândut ca un produs pe piaţă procesul de testare poartă
denumirea de testare beta (beta testing). Testarea beta presupune livrarea siste-
mului unui număr de potenţiali clienţi care sunt de acord să folosească sistemul.
Ei vor raporta problemele ı̂ntâlnite celor care dezvoltă sistemul. Acest tip de
utilizare reală a sistemului va evidenţia erori care nu au fost anticipate de cei
care construiesc produsul. În urma acestor reacţii sistemul este modificat şi
livrat fie pentru o nouă fază de testare beta, fie pentru vânzare.
95
Cazurile Datele Rezultatele Rapoarte
de test de test testului de testare
96
Date care cauzeaza
un comportament anormal
Date de test Ie
Program
Rezultate Oe
Date de test
testeaza deriveaza
la fiecare test.
97
T1
T1
A
T1 T2
A
A T2 B
T2 B T3
B T3 C
T3 C T4
D
T4
T5
98
poate datora trimiterii unor parametri având un alt tip decât cei ceruţi de
interfaţă, sau trimiterea ı̂ntr-o altă ordine a parametrilor, sau trimiterea
unui număr greşit de parametri.
• Neı̂nţelegeri legate de interfaţă. O componentă apelantă ı̂nţelege greşit
specificaţiile interfeţei şi face o presupunere eronată legată de comporta-
mentul componentei apelate. Această presupunere va cauza o eroare ı̂n
funcţionarea componentei apelante.
• Erori de timp. Apar ı̂n cazul sistemelor ı̂n timp real când se foloseşte
memorie partajată sau transmitere de mesaje.
1. testarea individuală a operaţiilor unui obiect. Acestea sunt funcţii şi pro-
ceduri. Pentru testarea lor se poate folosi testarea funcţională sau testarea
structurală.
If you think all change is for the better, why put it to the test?
— DISCOVERY CHANNEL, promo
99
100
Bibliografie
[2] Ivar Jacobson Grady Booch, James Rumbaugh. The Unified Modeling Lan-
guage User Guide. Addison-Wesley, 1999.
[3] Roy Miller Ken Auer. Extreme Programming Applied. Playing to Win.
Addison-Wesley, 2002.
[5] Roger Penrose. The Emperor’s New Mind. Penguin Books, 1989.
[6] James Rumbaugh, Michael Blaha, William Lorensen, Frederick Eddy, and
William Premerlani. Object-Oriented Modeling and Design. Addison-Wesley,
1991.
101