Sunteți pe pagina 1din 159

Cuprins

Introducere ......................................................................................................... 1. Programarea calculatoarelor ........................................................................


1.1. Limbaje de programare ........................................................................................................ 1.2. Implementarea algoritmilor ............................................................................................... 1.3. Lucrul cu fiiere .................................................................................................................... 1.4. Subprogramele ....................................................................................................................... 1.5. Instruciunea GoTo ..............................................................................................................

4 7 7 10 15 17 20 23 23 26 31 36 41 41 45 47 58 61 65 67 67 69 79 83 85

2. Ciclul de dezvoltare software .....................................................................


2.1. Activitatea de programare ................................................................................................. 2.2. Graful asociat unui program .............................................................................................. 2.3. Complexitatea programelor ............................................................................................... 2.4. Etapele ciclului de dezvoltare ...........................................................................................

3. Abordarea clasic ..........................................................................................


3.1. Specificaiile de programare ............................................................................................. 3.2. Preluarea algoritmilor ......................................................................................................... 3.3. Elaborarea schemelor logice .............................................................................................. 3.4. Scrierea programelor .......................................................................................................... 3.5. Testarea i implementarea programelor ........................................................................ 3.6. ntre art, meteug i industrie .....................................................................................

4. Programarea standard ..................................................................................


4.1. Reguli de construire ............................................................................................................. 4.2. Subprogramul ........................................................................................................................ 4.3. Generalitatea subprogramelor .......................................................................................... 4.4. Listele cu parametri ............................................................................................................ 4.5. Programul principal, programul apelator .........................................................................

5. Abordarea structurat .................................................................................


5.1. Reguli de baz ........................................................................................................................ 5.2. Programarea fr GoTo ...................................................................................................... 5.3. Conversii de programe ......................................................................................................... 5.4. Limbaje de programare structurate ................................................................................

89 89 94 97 102 106 106 110 113 118 122 122 125 128 129 129 132 134 140 140 141 149 150 153 156 158

6. Programarea modular ..................................................................................


6.1. Abordarea bottom-up .......................................................................................................... 6.2. Abordarea top-down ............................................................................................................ 6.3. Raportul subprograme modul .......................................................................................... 6.4. Parametrizarea .....................................................................................................................

7. Programarea orientat obiect ....................................................................


7.1. Proiectarea orientat obiect .............................................................................................. 7.2. Clasele ..................................................................................................................................... 7.3. Constructuri i destructori ............................................................................................... 7.4. Proprietile claselor ........................................................................................................... 7.4.1. ncapsularea ............................................................................................................ 7.4.2. Motenirea ............................................................................................................... 7.4.3. Polimorfism ..............................................................................................................

8. Utilizarea de componente ............................................................................


8.1. Premise .................................................................................................................................... 8.2. Software orientat pe componente ................................................................................... 8.3. Biblioteci de componente ................................................................................................... 8.4. Asigurarea interoperabilitii prin utilizarea de componente ...................................

9. Concluzii ...........................................................................................................
Anexa 1 Lista de variabile .......................................................................................................

Bibliografie ..........................................................................................................

Introducere
Obiectivul lucrrii este prezentarea tehnicilor de programare cu avantajele i dezavantajele lor, precum i realizarea unei analize comparate a complexitii software pentru entitile text generate cu ajutorul acestor tehnici, folosind aceeai problem spre exemplificare. Codul surs al programelor este considerat entitate text pentru c are n alctuire cuvintele unui vocabular i respect regulile de construire a elementelor complexe de limbaj asociate acestuia. Necesitatea lucrrii este dat de evidenierea progresului nregistrat de trecerea de la o tehnic veche de programare la una nou, n raport cu criteriul creterii performanei produselor software, dar i cu cel al creterii complexitii software. Mijloacele ntrebuinate sunt diferite ntruct fiecare dintre tehnicile de programare au promovat un anumit limbaj care a evideniat n primul rnd avantajele generate. Limbaje precum FORTRAN sau ALGOL sunt deja istorie, iar limbajul COBOL mai este prezent doar prin intermediul numeroaselor sisteme informatice dezvoltate cu el. Limbajul C i evoluia sa C++ sunt folosite n continuare foarte intens, n special ca limbaje de dezvoltare pentru sisteme de operare, ns limbaje precum Java sau C# reprezint la acest moment principalele instrumente de dezvoltare a produselor software. Limbajele de programare ofer resurse diferite, dac prin resurse se nelege: tipuri de date, cuvinte cheie asociate instruciunilor, implementarea recursivitii, blocurile, expresiile compuse i bibliotecile de funcii. Capitolele prezint caracteristicile tehnicilor de programare, ipotezele de lucru i efectele acestora asupra structurii produsului finit programul pe care l construiesc. Se fac referiri asupra capacitii tehnicilor de programare de a dezvolta lucrul n echip, de a asigura un nivel calitativ ridicat produsului software i de a permite transmiterea experienei de la un proces la altul prin reutilizarea de componente. Dezvoltarea tehnicilor de programare este dinamic. Pentru a identifica trendul evoluiei tehnicilor de programare se studiaz influena acestora asupra complexitii software. La finalul fiecrui capitol dedicat
4

Tehnici de programare

unei tehnici de programare, se analizeaz complexitatea software a codului surs generat cu ajutorul tehnicii respective pentru rezolvarea problemei alese. n capitolul n care se prezint Ciclul de dezvoltare software sunt descrise etapele, sarcinile, intrrile i ieirile acestora, aa cum decurg din standardele ingineriei software actuale. De asemenea, se prezint conceptul de complexitate software i se definesc instrumentele de msurare ce sunt folosite n cadrul acestei lucrri. Tehnica de programare clasic este prezentat ntr-un capitol distinct, n care se accentueaz caracterul artizanal, individual al muncii de programare. Arta programrii joac un rol important, ntruct fiecare program este vzut ca un produs unicat, produs ce include foarte mult munc intelectual, inspiraie i, desigur, inteligen. Programarea standard este o tehnic de programare care pentru prima dat ia n considerare necesitatea constituirii de biblioteci de subprograme, dup nite reguli foarte precise. Orice aplicaie apare, n viziunea programrii standard, sub forma exclusiv a apelului de subprograme. Multe dintre ideile de finalizare specifice programrii standard se regsesc n programarea orientat obiect. n capitolul Abordarea structurat se evit teoretizarea legat de o baz formal care impune i dezvolt aceast tehnic. Teorema de structur, ipotezele privind transformarea programelor sunt numai abordri de care practica programrii nu a inut seama n nici un fel. n acest capitol se prezint structurile fundamentale, cerinele pe care un program trebuie s le ndeplineasc pentru a fi considerat program structurat. Sunt prezentate, de asemenea, avantajele privind omogenitatea textelor surs, capacitatea de a dezvolta aplicaii structurate i extinderea pe care au luat-o limbajele de programare n care instruciunea GOTO nu mai trebuie folosit. Revoluia n programare prin introducerea de clase, obiecte, proprieti i dezvoltarea tehnicilor de analiz i proiectare bazate pe aceste concepte este abordat n capitolul Programarea orientat obiect. Se descriu structurile claselor, proprietile de ncapsulare, motenire i polimorfism precum i modul n care acestea influeneaz filosofia ntregii activiti de programare. Programarea orientat obiect reprezint altceva. Continuarea pstrrii vechilor mentaliti din programare devine imposibil. Saltul realizat de programatori este vizibil, iar rezultatele sunt dintre cele mai spectaculoase.

Introducere

Utilizarea de componente reprezint o extindere fireasc a programrii orientate obiect. Se pune problema reutilizrii funcionalitii i nu neaprat a codului care o implementeaz. Sunt prezentate tehnici de definire a componentelor, utilizarea acestora n cadrul aplicaiilor eterogene din punct de vedere al limbajelor de programare i/sau tehnologiilor folosite la dezvoltarea lor, importana componentelor n implementarea interoperabilitii aplicaiilor. Lucrarea se ncheie cu concluzii n care se evideniaz necesitatea sintetizrii experienelor pozitive n vederea trecerii la noi tehnici de programare. Exemplificrile se fac numai n limbajul C++. Se definete problema PROB care este prezentat n capitolul Ciclul de dezvoltare software. n celelalte capitole sunt date soluii corespunztoare fiecrei tehnici de programare analizate pentru problema PROB. S-a adoptat aceast modalitate de lucru pentru a putea fi comparate efectele utilizrii fiecrei tehnici de programare n cazul implementrii aceluiai algoritm. S-a ales o problem cunoscut pentru a facilita urmrirea pailor algoritmului, simultan cu structurile de program pe care fiecare tehnic le genereaz. Analiza comparat se realizeaz prin soluionarea aceleai probleme, pentru a surprinde mai bine, diferenele de abordare pentru fiecare dintre tehnicile de programare. Pentru fiecare soluie se fac comentarii privind lungimea codului surs i complexitatea programelor. Autorii aduc mulumirile lor membrilor Catedrei de Informatic Economic din Academia de Studii Economice i, n special, colectivelor de programarea calculatoarelor ale cror lucrri au stat la baza cercetrilor ntreprinse i la obinerea rezultatelor incluse n capitolele destinate celor mai noi tehnici de programare aflate acum n atenia dezvoltrii de aplicaii informatice moderne. Lucrarea este elaborat n cadrul contractului de cercetare INFOSOC Sistem de evaluare a entitilor bazate pe text, nr.148/29.09.2004. Autorii mulumesc tuturor celor care, prin contribuii i sugestii, vor mbunti ediia viitoare a lucrrii de fa, lucrare care se adreseaz tuturor celor care dezvolt programe, pentru a gsi noi resurse i pentru a se perfeciona continuu.

1.1 Limbaje de programare


Limbajele de programare sunt elaborate pentru a implementa algoritmi. Orice algoritm se descrie ca succesiune de pai n care intervin operanzi i operatori pentru efectuarea de prelucrri. Orice limbaj de programare conine: o list de operatori care arat care sunt operaiile aritmetice, logice i de compunere pe care le accept limbajul, devenind resurse la dispoziia programatorilor atunci cnd construiesc expresii mai simple sau mai complexe; lista operatorilor conine i prioritile asociate precum i regula de evaluare; o list a cuvintelor cheie asociate unor comenzi executabile; este preferabil s existe o continuitate de la un limbaj la altul, pentru a nu se crea confuzii; aa se explic faptul c pentru implementarea structurii alternative se pstreaz construcia if() then else, pentru implementarea structurii repetitive se pstreaz instruciunile for(), while(), do until(), cu mici variaii; o list a cuvintelor cheie pentru definirea tipurilor de date fundamentale; o list de cuvinte cheie care joac rolul de atribute sau de specificatori; o list de delimitatori de blocuri i de instruciuni; mecanisme de construire a constantelor i identificatorilor; mecanisme de construire a expresiilor de definire i a expresiilor de referire; mecanisme de construire a subprogramelor; mecanisme de implementare a structurilor de control.
7

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Orice limbaj are la baz un alfabet i un vocabular format din cuvinte cheie i cuvinte construite de utilizatori. Limbajele de programare au nregistrat evoluii spectaculoase, trecnd prin stadii care au impus modificri sau chiar dispariia. Aa s-a ntmplat cu limbajul FORTRAN, care a devenit n evoluia sa FORTRAN-4, FORTRAN-77, FORTRAN-90, iar variantele care au urmat au avut o asimilare limitat, limbajul fiind cu o rspndire extrem de redus. n schimb limbajul C++ prin capacitatea sa de a asimila construcii cu grad de complexitate foarte variat, s-a impus i s-a dezvoltat. Orientarea spre programarea vizual are o larg rspndire prin sugestivitatea abordrii n raport cu problema de rezolvat i operaiile mecanice pe care le presupune implementarea unui algoritm. Limbajele de nivel sczut presupun instruciuni pentru operaiile elementare. Programatorul trebuie s gestioneze descompunerea expresiilor pentru evaluarea din aproape n aproape. Limbajele de nivel ridicat includ construcii complexe, compuneri de expresii i prin atribuirea de calificative se obin efecte speciale n ceea ce privete referirile de operanzi i operatori. Sunt implementate structuri dintre cele mai variate, iar mecanismele de definire de operanzi i operatori au corespondent mecanisme de referire care genereaz efecte ce asigur generalitate i eficien tuturor construciilor; numai aa se explic creterea complexitii i diversitii aplicaiilor informatice de azi. Exemplificarea limbajelor de programare este realizat folosind numai limbajul C++. Elementele care definesc un limbaj sunt: alfabetul limbajului, vocabularul, operatorii i precedenele lor, identificatorii, declaraiile de funcii i variabile. Vocabularul limbajului C++ include cuvintele cheie: asm catch continue dynamic_cast false if namespace public signed switch try unsigned wchar_t auto char default else float inline new register sizeof template typedef using while bool class delete enum for int operator reinterpret_cast static this typeid virtual break const do explicit friend long private return static_cast throw typename void case const_cast double extern goto mutable protected short struct true union volatile
8

Programarea calculatoarelor

Lista de operatori i prioritile sunt date n tabelul 1.1: Operatorii identificai n limbajul C++ Tabelul 1.1
Preceden Operatori 1 () [] :: ~ 2 ! - (operator unar) * (dereferire) & (adresa) Sizeof 3 ->* .* 4 * (nmulire) / 5 + 6 << >> 7 < <= 8 == != 9 & ( AND pe bii) 10 ^ 11 | 12 && 13 || 14 ?: 15 = += 16 , -> ++ . --

% > >=

-=

etc.

Alfabetul limbajului C++ este alctuit din urmtoarele caractere:


abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123 56789 !#%&()*+,-./ :;<=>?[\]^_{|}~ spaiu, TAB, CR/LF

Identificatorul este numele dat de programator variabilelor, funciilor, etichetelor i a altor obiecte definite de el. Mecanismul de construire al acestuia este acelai n toate limbajele de programare importante: primul caracter este o liter sau un caracter de subliniere, iar caracterele care urmeaz sunt litere, cifre sau caractere de subliniere. Cuvintele cheie asociate limbajului nu sunt acceptate ca identificatori.
9

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Exemple de identificatori valizi sunt: _matrice, mat1234, arb43bin, for123. Exemple de identificatori invalizi sunt: 12matrice, for, etc. Prototipul de funcie n C++ este urmtorul:
tip_rezutat nume_funcie ( list_parametrii ) { corp_funcie }

Declararea operanzilor se face astfel:


tip_operand list_de_variabile;

Exist numeroase lucrri, [IVANI98], [SMEU01], [SMEU02], [STROU87], care detaliaz limbajul C++ evideniind caracteristicile sale cele mai puternice, studiul acestui limbaj nefiind obiectivul acestei lucrri.

1.2 Implementarea algoritmilor


Algoritmii presupun operanzi i operatori. Pentru operanzi exist: iniializri de date; afiri de rezultate; prelucrri.

Operatorii arat modul n care sunt transformai operanzii, pentru a deveni din date iniiale, date prelucrate, adic rezultate care s determine aciuni sau s permit luarea unor decizii. Orice problem P are asociat un algoritm cruia i corespunde structura arborescent cu dou niveluri dat n figura 1.1.

Figura 1.1 Structur de algoritm pe dou niveluri

10

Programarea calculatoarelor

Iniializarea se realizeaz prin: citire date din fiiere sau baze de date; introducere date de la tastatur; evaluarea expresiilor de atribuire. afiare rezultate pe ecranul monitorului; scrierea la imprimant; creare sau actualizare de fiiere, respectiv actualizare de baze de date.

Secvena de rezultate conine proceduri pentru:

Implementarea unui algoritm include instruciuni pentru una sau mai multe combinaii de iniializare, respectiv gestionare a rezultatelor. Exist numeroi algoritmi dai n literatura de specialitate i n crile de baz ale programrii. Sunt algoritmi verificai, adui la o form rafinat, programatorul trebuind numai s-i preia. Sunt i situaii n care, programatorul trebuie s-i construiasc algoritmi proprii. n toate cazurile, trebuie avute n vedere: generalitatea pe care trebuie s o asigure, nefiind interesant acel algoritm care soluioneaz o problem concret, ci acela care soluioneaz problemele aparinnd unei clase; corectitudinea, n sensul c pentru orice problem aparinnd clasei de probleme pentru care a fost construit algoritmul, trebuie s furnizeze rezultate corecte; reproductibilitatea, n ideea c repetnd prelucrrile pentru aceleai date, se vor obine aceleai rezultate, prelucrrile avnd caracter determinist; finitudine, n sensul c volumul de prelucrri trebuie limitat la o dimensiune acceptabil n raport cu obiectivul urmrit.

La implementarea unui algoritm se procedeaz mai nti la elaborarea unei scheme logice. Cu acest prilej, se analizeaz gradul de nelegere a problemei. Testul de birou folosind date de control are menirea de a da un plus de siguran soluionrii problemei prin metoda folosit. Pentru implementarea algoritmului sunt alese niveluri de detaliere. Este important ca indiferent de procedeul definit i utilizat, programul sa-i
11

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

ating obiectivul pentru care a fost elaborat. De exemplu, se dorete implementarea algoritmului de sortare prin interschimbare cu contorizarea interschimbrilor. Se consider irul:

i se dorete ordonarea descresctoare. Se interschimb perechile, ncepnd cu primul element:

irul devine:

Numrul de interschimbri a fost 4. Se interschimb perechile ncepnd cu al doilea element:

irul devine:

Numrul de interschimbri a fost 3. Se reiau interschimbrile cu primul element:

12

Programarea calculatoarelor

irul devine:

Numrul de interschimbri a fost 4. Se interschimb ncepnd cu al doilea element:

irul devine:

Numrul interschimbrilor a fost 3. Se reiau paii:

13

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Algoritmul este finit pentru c n momentul n care nu mai exist interschimbri, nseamn ca irul este sortat. Pentru implementare trebuie rspuns la ntrebrile: ct de lungi sunt irurile de termeni care se sorteaz; dac sortarea este nsoit i de interschimbarea altor cmpuri.

Funcie de rspunsurile date se procedeaz la definirea unui algoritm de sortare n fiiere sau la construirea unui algoritm de sortare exclusiv n memorie. Implementarea algoritmilor depinde de: experiena programatorilor; resursele hardware i software disponibile; resursele financiare care stau la baza demersului; timpul n care trebuie rezolvat problema.

n mod normal, trebuie s se porneasc de la problema de rezolvat. Aceasta impune cum se stocheaz datele iniiale, cum se gestioneaz rezultatele intermediare i cum sunt memorate rezultatele finale. Implementarea algoritmilor necesit efectuarea de calcule privind necesarul de memorie pentru a stoca rezultatele intermediare i finale, precum i datele iniiale n timpul prelucrrii. Sunt preferai algoritmii care nu necesit zone importante de memorie pentru rezultate intermediare. Pentru calculul mediei aritmetice care utilizeaz ct mai puin memorie, programul ce implementeaz algoritmul este urmtorul:
#include <stdio.h> int main() { int i, n, s, x; float xm; s = 0; printf("Introduce numarul scanf("%d", &n); for ( i = 0; i < n; i++ ) printf( "Introduce scanf("%d", &x); s += x; } xm = (float)s/n; printf( "Media aritmetica }

de elemente:"); { x[%d] = ", i );

este %f", xm );

14

Programarea calculatoarelor

Se constat c pentru a reutiliza datele pentru alte calcule, acest deziderat este imposibil de realizat. Pentru a reutiliza datele, este necesar ca ele s se salveze n memorie, n structuri de date corespunztoare, i apoi s intre n prelucrarea efectiv. Algoritmul este un aspect, programul este o concretizare, una din concretizri, totul depinznd de programator.

1.3 Lucru cu fiiere


Fiierele, bazele de date, sunt fundamentale pentru rezolvarea problemelor n care se manipuleaz volume mari de date. Fiierul este o colecie de date reprezentnd informaii privind elementele unei colectiviti. Dac datele privind un element Ai al colectivitii {A1, A2, ., An} are lungime constant L baii, atunci fiierul F are o lungime lg(F) = n * L baii. Fiecare articol descrie un element al colectivitii. Poziia pi a articolului care se refer la elementul Ai din colectivitate mpreun cu o valoare unic, numit cheie, notat ki, formeaz o pereche ( ki, pi). Unui fiier F i se asociaz un ir de perechi (k1, p1), (k2, p2), ..., (kn, pn). Dac se efectueaz operaii precum adugarea, inserarea, tergerea, interschimbarea de articole, este preferabil ca ele s se efectueze asupra irului de perechi, fr a provoca schimbri la nivel fizic, ntruct operarea pe zonele de memorie asociate fiierului au durate care reduc volumul tranzaciilor pe unitatea de timp. Dac ntre cheile k1, k2, .........., kn i poziiile p1, p2, ...., pn se identific o dependen, atunci se construiete o expresie analitic folosind relaia: pi = f (ki) Se obine deplasarea articolului Ai prin relaia: Di = pi * LAi Problemele se trateaz similar i n cazul n care lungimile articolelor sunt diferite. Dac articolul Ai are o lungime proprie Li, deplasarea sa Di se obine din relaia:

Di = LA j + D0
j =1

i 1

unde D0 este deplasarea primului articol.

15

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Pentru a crete viteza de identificare a unui articol, fiierul F este mprit n r pri, figura 1.2.

Figura 1.2 Divizarea fiierului F

Dac se efectueaz traversarea fiierului F pentru a gsi articolul cu cheia kx, sunt necesare suficient de multe operaii de citire. Dac se construiete irul de r perechi (k1`, p1`), (k2`, p2`)..(kr`, pr`) se traverseaz mai nti irul de perechi, se obine selectarea zonei din fiier unde se afl articolul cu cheia kx dup care se procedeaz la traversarea secvenial a zonei, articol cu articol, pn la identificarea celui cutat. Este important ca de la nceput articolele s fie dispuse n zonele fiierului F cu condiia: k1 < k2 < .. < kn Subirului de perechi i se asociaz un alt subir, cutarea secvenial efectundu-se pe dou niveluri. Raionamentul se dezvolt, fiind necesar un echilibru ntre numrul nivelurilor de indexare i efortul de traversare secvenial n cadrul fiecrui nivel. Dac se adaug atribute, se construiesc tripletele care se asociaz articolelor fiierului (k1,p1,a1), (k2,p2,a2), ...., (kn,pn,an). Operaiile de intersecie, reuniune de iruri de triplete conduc la extragerea din fiier a articolelor ale cror cmpuri au valori ce corespund unor combinaii de atribute. Viteza de derulare a tranzaciilor depinde strict de ntreaga filosofie de a organiza procesele de referire ale articolelor din zona de date a fiierului. Lucrul cu indexuri, cu deplasri i mai ales structurile arborescente asociate perechilor de cutare influeneaz duratele tranzaciilor.

16

Programarea calculatoarelor

1.4 Subprogramele
Acum se concepe dezvoltarea unei aplicaii numai folosind subprograme. Un subprogram este o entitate de sine stttoare, care concentreaz o prelucrare cu caracter repetitiv. Nu se scriu subprograme pentru prelucrri care nu vor mai fi realizate i cu alte prilejuri. Subprogramul are un nume sugestiv, uor de manevrat, fr a fi definite mai multe subprograme diferite ca prelucrare cu nume avnd coeficient de similitudine peste un prag considerat limit superioar. Spre exemplificare, se consider urmtoarea list de subprograme:

read_file() subprogram care citete un articol dintr-un fiier; update_file() subprogram pentru actualizarea unui fiier; write_file() subprogram pentru scrierea unui articol ntr-un fiier; addmat() subprogram care adun dou matrice; prodmat() subprogram care nmulete dou matrice; copymat() subprogram pentru copierea unei matrice ntr-o alt matrice; initmat() subprogram care iniializeaz o matrice cu o constant; sort_file() subprogram pentru sortarea fiierelor; sort_vect() subprogram pentru sortarea elementelor unui vector; concat_vect() subprogram care concateneaz doi vectori; concat_lists() subprogram care concateneaz dou liste simple; concat_listd() subprogram pentru concatenarea dou liste duble; concat_nlists() subprogram pentru concatenarea a n liste simple; concat_nlistd() subprogram care concateneaz n liste duble; concat_nvect() subprogram care concateneaz n vectori.
17

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Subprogramele conin n construciile lor:

liste de parametri formali n care se regsesc operanzii care fac obiectul prelucrrii, operanzii ce conin rezultatele i variabile ce conin informaii privind modul n care s-au efectuat prelucrrile; listele fixe de parametri au aceeai structur i lungime, indiferent de numrul apelurilor; listele variabile au att tipuri diferite de parametrii, ct i numr variabil;
instruciuni care asigur revenirea n programul apelator, return; este preferabil s se construiasc subprograme care conin o singur instruciune return, folosind fie compuneri de expresii, fie o variabil de control utilizat ulterior; instruciuni repetitive pentru a asigura traversarea structurilor de date omogene (masiv, list, arbore, fiier), dac pentru evaluarea de expresii acest lucru este necesar; instruciuni de iniializare pentru variabile care i modific coninutul n vederea returnrii de rezultate care vor fi utilizate n programul apelator; programul apelator este i el tot un subprogram; int main() este, de asemenea, un subprogram, aa cum ntr-un arbore binar, rdcina este tot un nod; un tip de rezultat care se returneaz; n cazul n care lista rezultatelor returnate este vid, tipul subprogramului este void.

Forma general a unui subprogram este:


tip_rezultat nume_subprogram( list_parametrii_formali ) { definiri variabile locale subprogramului instruciuni de prelucrare return ( expresie ) }

Figura 1.3 Forma general a unui subprogram

Este de dorit ca subprogramele s fie nzestrate cu un grad nalt de generalitate pentru a permite refolosirea lor ori de cte ori e nevoie. Testarea sistematic a subprogramelor le d un nivel de corectitudine care genereaz ncrederea utilizatorilor n a le ncorpora n programele proprii. Exist mai muli termeni care desemneaz acelai lucru: proceduri, subprograme, funcii; sunt concepte prin care, de regul, se nelege o construcie independent n raport cu un context, care se refer i care permite efectuarea de prelucrri ale cror efecte sunt utilizate ulterior.
18

Programarea calculatoarelor

Pentru evaluare expresiei:


S = xi
i =1 n

se scriu mai multe forme de subprograme, care difer dup cum sunt transmii parametrii. n textul surs:
int suma ( int x[], int n ) { int s, i; for ( s = 0, i = 0; i < n ; i++ ) { s += x[i]; } return s; }

subprogramul returneaz rezultatul. n textul:


void suma ( int x[], int n, int* ps ) { int i; *ps = 0; for ( i = 0; i < n; i++ ) { *ps += x[i]; } }

rezultatul se regsete n zona de memorie a crei adres se afl n variabila pointer ps. Faptul c lista de parametri include o mare diversitate de tipuri de date, inclusiv pointeri spre funcii, subprogramele devin cu grad de generalitate foarte mare. n loc s se scrie, de exemplu, dou subprograme pentru a gsi elementul minim, respectiv elementul maxim dintr-un ir, se va scrie un singur subprogram ce are n lista de parametri o funcie ce returneaz evaluri diferite de expresii condiionale, care vor determina aciuni diferite n cadrul subprogramului. Subprogramele trebuie s fie generale att prin dimensiunea problemelor de rezolvat, ct mai ales prin cuprinderea a ct mai multor cazuri care definesc clasa de probleme rezolvat. n programarea orientat obiect problematica tipului de rezultate returnate i a tipurilor de variabile din lista de parametrii se soluioneaz prin construcii de tip template. Limbajele de programare dispun de numeroase modaliti de transmitere a parametrilor, dintre care transmiterea prin valoare,
19

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

transmiterea prin adrese i transmiterea prin referin, sunt cele mai frecvent ntlnite. Este rezonabil cunoaterea n detaliu a acestor mecanisme pentru a nelege efectele. Dac n cazul transmiterii prin valoare operarea pe variabilele asociate parametrilor subprogramului este local n raport cu domeniul definit de subprogram, n celelalte cazuri aceste operaii conduc la modificarea coninutului zonelor de memorie asociate parametrilor formali, la nivelul subprogramului apelator. Subprogramele nu conin operaii de intrare/ieire, pentru a li se asigura un nalt grad de generalitate i mentenabilitate. Ele primesc datele de intrare prin intermediul listei de parametrii i ofer rezultate fie prin parametrii din list, fie prin valoarea returnat de subprogram, fie prin amndou modalitile.

1.5 Instruciunea GOTO


Aceast instruciune a fost mrul discordiei de-a lungul timpului pentru programatori. Ea nseamn salt necondiionat spre o instruciune a crei etichet este specificat. Salturile napoi revin la situaiile n care eticheta e1 spre care se efectueaz saltul necondiionat precede instruciunea GOTO, figura 1.4. e1

e2

GO TO e1

Figura 1.4 Instruciune salt napoi

Salturile nainte revin situaiilor n care etichetele e2 i e3 ale instruciunilor spre care se efectueaz saltul urmeaz instruciunilor GOTO, figura 1.5.

20

Programarea calculatoarelor

Figura 1.5 Instruciune salt nainte

Dac se asociaz un graf unui program i se include ntr-o matrice instruciunile precedente i instruciunile urmtoare, n cazul unei structuri liniare, figura 1.6, matricea include asteriscuri numai deasupra diagonalei principale:

Figura 1.6 Structur liniar

Figura 1.7 Matricea de preceden a instruciunilor

n cazul includerii n program a instruciunilor de salt necondiionat, matricea precedenelor devine mult mai complex. Pentru programul al crui graf este dat n figura 1.8, rezult matricea de preceden, din figura 1.9.

21

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Figura 1.8 Graf asociat unui program ce include instruciuni de salt

I1 I1 I2 I3 I4 I5 I6 I7

I2

I3

I4

I5

I6 I7

Figura 1.9 Matricea de preceden asociat programului cu salturi mixte

Programarea modular exclude apariia instruciunii GOTO, dei la nivelurile de programare n limbaj de asamblare este evident c nici o structur de control nu se implementeaz fr a folosi aceast instruciune. Sunt situaii n care optimizarea programelor impune o alt abordare care s elimine salturile necondiionate ntre componente aflate n segmente diferite. Programarea calculatoarelor se definete ca meserie ce folosete resurse, iar eficiena sa este cu att mai mare cu ct procesul de alocare i nivelare a acestor resurse este mai aproape de nivelul optim. Limbajele, subprogramele, instruciunile, tehnicile de programare sunt resurse, nivelarea i alocarea lor o efectueaz programatorul.

22

2.1 Activitatea de programare


Activitatea de programare, aa cum este definit n [MSPCD97], reprezint arta i tiina de a crea programe pentru calculator. Programarea ncepe cu cunoaterea unuia sau a mai multor limbaje de programare, cum sunt Basic, C, C++, Java, Pascal sau limbajul de asamblare. Cunoaterea unui limbaj nu este suficient pentru realizarea unui program bun. Alte aspecte necesare se refer la teoria algoritmilor, proiectarea interfeelor cu utilizatorul i caracteristici ale dispozitivelor hardware. Activitatea de programare este colectiv, echipele de programatori dezvolt procese de alegere i nivelare a resurselor - echipamente hardware, limbajele de programare, algoritmii - pentru a obine un software de cea mai bun calitate. Programatorii sunt persoane cu nalt calificare care scriu i depaneaz programe. n funcie de dimensiunea proiectului i de mediul de lucru, un programator lucreaz singur sau ntr-o echip, implicat parial sau total n procesul de dezvoltare, care ncepe cu faza de analiz i se ncheie cu faza de testare i implementare. Activitatea de programare este deosebit de complex, de dinamic i implic eforturi deosebit de mari pentru actualizarea cunotinelor, pentru nelegerea corect a instrumentelor de dezvoltare a aplicaiilor. Programatorii trebuie s fie la curent cu ultimele nouti n domeniu, s i extind permanent aria de cunoatere spre noi limbaje i tehnologii. Programarea presupune existena sistemelor de calcul i a software necesar pentru dezvoltarea de noi produse, n vederea satisfacerii unor cerine precis definite. Acest software reprezint sistemul de programare i include urmtoarele categorii de instrumente: programele editoare de text, programele translatoare, programele editoare de legturi, programele depanatoare i mediile de programare. Pentru a dezvolta software de baz, au fost create specializri, unii dintre programatori stpnind foarte bine limbajele de asamblare. Alii, pentru a dezvolta software cu caracter aplicativ, utilizeaz limbajele de nivel
23

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

nalt. n cazul aplicaiilor care opereaz cu seturi foarte mari de date, programatorii acumuleaz experien n a lucra cu sisteme complexe de gestiune a bazelor de date. n contextul creterii complexitii aplicaiilor informatice s-au cristalizat urmtoarele direcii: activitatea de programare este o activitate care se deruleaz n cadrul unei echipe, n care fiecare membru are definite inputurile, respectiv outputurile, foarte clar; s-au adncit specializrile, nct rolul analistului de sistem, rolul designerului, rolul programatorului i rolul celor care se ocup de testare, implementare i mentenan a crescut foarte mult; deja exist profesiuni foarte bine conturate, iar managerul de proiecte IT este deja o profesie necesar i, mai ales, recunoscut n societatea informaional; necesitatea utilizrii de instrumente tehnice vzut ca necesitate a nzestrrii posturilor de munc, fie c e vorba de analiti, de designeri, de programatori, de testeri de software i de personal care administreaz aplicaia.

Activitatea de programare este privit, uneori, ca activitate pur de creaie, aspect exagerat, cum tot exagerat este a-l privi pe programator ca pe un simplu codificator. Programatorul trebuie s se instruiasc continuu, forma concret programul a ntregii activiti dintr-o companie de software este rezultatul muncii sale, chiar dac n spate se afl eforturile concertate i ale analitilor i designerilor. Apar numeroase ntrebri referitoare la: numrul limbajelor de programare pe care trebuie s le cunoasc un programator; dac programatorul stpnete foarte bine un limbaj de programare, are experien n a folosi facilitile respectivului limbaj, posed cunotine de algoritmi i tehnici de programare i dac stpnete elementele de baz ale unui sistem de operare, va dezvolta produse de bun calitate; atunci cnd un alt limbaj de programare devine dominant, se impune ca programatorul s treac la elaborarea de software folosind resursele noului limbaj dominant; nseamn c activitatea de programare presupune un continuu efort de instruire, dar, mai ales, autoinstruire;

24

Ciclul de dezvoltare software

traiectoria pe care o urmeaz un programator; dac acesta e o persoan perseverent adncete cunotinele dintr-un domeniu sau extinde aria de cuprindere spre alte limbaje sau tehnici de programare; o traiectorie normal este aceea n care programatorul se ndreapt spre activitatea de proiectare, iar dup ce capt o mai mare experien se orienteaz spre analiza de sistem i spre a deveni manager de proiect; caracterul industrial al activitii de programare; conceptul de fabric de software este privit ca o translatare forat a unor laturi cu caracter repetat, reproductibil i responsabilizat din producia industrial spre o zon unde imaterialitatea produsului imprim particulariti mai ales legate de absena uzurii fizice i de costul nul al operaiei de copiere; necesitatea de a compara produsele software prin definirea de metrici ale calitii, prin utilizarea unor coeficieni de transformare; apariia pieii de software ca principal prghie de reglare a tendinelor centrifuge din domeniul produciei de aplicaii informatice cu grad de generalitate deosebit de ridicat.

Activitatea de programare a calculatoarelor presupune caliti remarcabile din partea celor care doresc s profeseze meseria de programator. Piaa de joburi n evoluia sa a impus meserii deosebit de diverse, cum sunt: programator, dezvoltator, inginer software, inginer de sistem etc. Pentru analizarea avantajelor i dezavantajelor tehnicilor de programare prezentate n aceast carte, a fost aleas o problem comun, care este dezvoltat folosind tehnicile prezentate. Se presupune o matrice cu m linii i n coloane, m i n numere impare. Pentru aceasta se determin valorile maxime i minime, se testeaz simetria matricei, iar dac matricea este simetric, atunci se numr elementele pozitive, negative i nule ale acesteia. Dimensiunile i elementele matricei sunt informaii ce vor fi citite de la tastatur, n programele de test.

25

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

2.2 Graful asociat unui program


Orice program este alctuit din instruciuni neexecutabile, prin care se definesc operanzii i operatorii, ct i prin instruciunile executabile I1, I2, .., In. Lungimea L a unui program este dac ca numr de instruciuni. ns nu exist o coresponden biunivoc ntre o instruciune i o linie din codul surs. O linie din codul surs poate conine 0, 1 sau mai multe instruciuni. Programul:
int main () { int a, b, c, d, e, f; a = b = c = 7; d = 89; e = -1; if ( e + d * a ) f = e + a; else f = e - a; }

are un numr de zece linii surs. n cazul n care un alt programator rescrie acelai program sub forma:
int main () { int a, b, c, d, e, f; a = b = c = 7; d = 89; e = -1; if ( e + d * a ) f = e + a; else f = e - a;}

se obine un program cu doar ase linii surs, ns ambele au acelai numr de instruciuni. Se impune stabilirea unor reguli foarte precise pentru dispunerea instruciunilor i separatorilor de blocuri pentru a se obine construcii comparabile ca efort de realizare i claritate a codului. n graful asociat unui program, fiecrei instruciuni i se asociaz un nod, legarea acesteia de instruciunea ce urmeaz a fi executat realiznduse cu ajutorul unui arc orientat.

26

Ciclul de dezvoltare software

Textul surs al programului pentru alegerea minimului dintre trei elemente este urmtorul:
int main () { int a, b, c, min; printf( "Introduceti a = " ); scanf("%d", &a); printf( "Introduceti b = " ); scanf("%d", &b); printf( "Introduceti c = " ); scanf("%d", &c); if ( a > b ) { if ( b > c min } else { min } } else { if ( a > c min } else { min } } I1 I2 I3 I4 I5 I6 I7 I8 I9 I10 I11 I12 I13 I14 I15 I16 I17

) { = c; = b;

) { = c; = a;

printf( "Minimul este %d", min); }

I18

i are asociat structura arborescent dat n figura 2.1.

27

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Figura 2.1 Graful asociat programului pentru alegerea minimului dintre a, b, c

Secvena de program destinat numrrii elementelor pozitive, negative i nule ale unei matrice este urmtoarea:
int splus = 0; int snegativ = 0; int snul = 0; for ( i = 0;i < m; i++ ) { for ( j = 0; j < n; j++ ) { if ( a[i][j] > 0 ) splus++; if ( a[i][j] < 0 ) snegativ++; if ( a[i][j] == 0 ) snul++; } } printf("\nNumarul de elemente pozitive este %d", splus ); printf("\nNumarul de elemente negative este %d", snegativ ); printf("\nNumarul de elemente nule este %d\n", snul ); I1 I2 I3 I4 I5 I6 I7 I8

I9 I10 I11

28

Ciclul de dezvoltare software

iar graful asociat este dat n figura 2.2.

Figura 2.2 Graf asociat secvenei de numrare a elementelor

Graful asociat unui program permite evidenierea modului n care este construit programul. Pentru programul:
int splus int snegativ = 0; int snul = 0; = 0; I1 I2 I3 I4 I5 I6 I7 I8 I9 I10 I11 I12

for ( i = 0;i < m; i++ ) { for ( j = 0; j < n; j++ ) { if ( a[i][j] > 0 ) { splus++; } else { if ( a[i][j] < 0 ) { snegativ++; } else { snul++; } } } }

29

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

printf("\nNumarul de elemente pozitive este %d", splus ); printf("\nNumarul de elemente negative este %d", snegativ ); printf("\nNumarul de elemente nule este %d\n", snul );

I13 I14 I15

este dezvoltat graful din figura 2.3.

Figura 2.3 Graful asociat programului cu structuri alternative imbricate

Abordarea structurii graf permite dezvoltarea de operaii de transformare care s conduc la construcii echivalente, ns optimizate. Numrul de arce i orientarea acestora deosebete tehnicile de programare.

30

Ciclul de dezvoltare software

2.3 Complexitatea programelor


Complexitatea software este definit n standardul IEEE 729 1983 ca fiind gradul de complicare a unui sistem sau a unei componente dintr-un sistem, determinat de factori cum sunt numrul i complexitatea interfeelor, numrul i complexitatea ramurilor condiionale, gradul de imbricare, tipurile structurilor de date i alte caracteristici ale sistemului. O definiie mult mai complet a fost cea dat de Zuse n 1991, i anume, complexitatea software este gradul de dificultate n analiza, ntreinerea, testarea, proiectare i modificarea software-ului. Rezult c, este de ateptat ca diferite tipuri de complexitate s apar n diferite etape ale ciclului de dezvoltare. Intuitiv, fiecare programator i d seama ca un program este mai simplu sau mai complex. Se spune c un program este mai simplu dac are mai puine instruciuni i dac legturile dintre instruciuni sunt mai reduse ca numr i ca importan. Se consider un program PR cruia i se asociaz o structur de tip graf n care se noteaz: na - numrul arcelor nn - numrul nodurilor din graf Complexitatea n sens McCabe CM a unui program este dat de relaia: CM = na nn + 2 Complexitatea n sens McCabe sau complexitatea ciclomatic, este cea mai utilizat metric software a complexitii. Ea msoar numrul de ci de execuie liniar independente, printr-un modul de program. Aceast msur ofer ca rezultat un singur numr care servete ca instrument de comparaie cu complexitatea altor programe. O aplicaie frecvent a complexitii ciclomatice este compararea rezultatului obinut cu un set de valori-prag recunoscute. Un astfel de set este dat n tabelul 2.1.

31

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Complexitatea ciclomatic Tabelul 2.1 Complexitate ciclomatic 1 10 11 20 21 50 mai mare de 50 Evaluarea riscului un modul/program simplu, fr risc mare un modul/program mai complex, cu risc mediu un modul/program foarte complex, cu risc ridicat un modul/program netestabil, cu un risc extrem de ridicat

Dac un program este format din instruciunile I1, I2, , IK, crora li se asociaz graful dat n figura 2.4.

Figura 2.4 Structur secvenial de program

Complexitatea CM = 1 pentru c: na nn = K1 = K

Pentru programul cu structura de graf dat n figura 2.5, complexitatea CM = 14 10 + 3 = 6, pentru c numrul de arce este 14, iar numrul de noduri este 10.

32

Ciclul de dezvoltare software

Figura 2.5 Structur de program cu salturi napoi

Pentru programul de alegere a elementului minim i a elementului maxim dintr-un ir dat prin textul surs:
int x[N], i, n, minim, maxim; n = citeste(); //functie de pentru numarul de elemente citeste(n, x); // functie de citire pentru elemente maxim = minim = x[0]; for ( i = 0; i < n; i++ ) { if ( minim > x[i] ) { minim = x[i]; } if ( maxim < x[i] ) { maxim = x[i]; } } printf( "Maximul este %d\n", maxim ); printf( "Minimul este %d\n", minim );

33

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

cu graful asociat dat n figura 2.6, complexitatea este CM = 13 11 + 2 = 4


1 2 3 4 if(min > x[i]) 12 min = x[i] 13 11 if (max < x[i]) 9 max = x[i] 10 i++ 5 6 7

Figura 2.6 Graf asociat programului de alegere a minimului i maximului

Se observ c de la o tehnic de programare la alta difer nivelul complexitii n sens McCabe. O alt metric a complexitii software o reprezint complexitatea Halstead. Ea a fost dezvoltat n special pentru a msura complexitatea unui modul de program pe baza codului surs, cu accent pe complexitatea de calcul. Metricile Halstead se bazeaz pe patru valori numerice, rezultate din codul surs: n1 n2 - numrul de operatori distinci - numrul de operanzi distinci

N1 - numrul total de operatori N2 - numrul total de operanzi


34

Ciclul de dezvoltare software

Din aceste numere, rezult cinci metrici: Metric Lungimea programului Vocabularul programului Volumul Dificultatea Efort Simbol N n V D E Formula N = N1 + N2 n = n1 + n 2 V = N * log2n D = (n1/2)*(N2/n2) E=D * V

Volumul modulului, V, reprezint coninutul informaional al modulului. El descrie dimensiunea implementrii unui algoritm. Calculul lui V este bazat pe numrul de operaii realizate i de numrul de operanzi cu care lucreaz algoritmul. Astfel determinat, volumul unei funcii trebuie s rezulte ntre valorile 20 i 1000. Un volum mai mare de 1000 reprezint o indicaie c funcia respectiv conine mult prea multe prelucrri. Volumul unui fiier cu cod surs trebuie s se gseasc ntre 100 i 8000. Complexitatea n sens Halstead CH este dat de relaia: CH = N1 log2N1 + N2 log2 N2 Astfel, pentru secvena:
a b c d = = = = 7; 8; a + b; a * c + b * ( a 1 )

prin numrare operanzi i operatori N1 = 10, N2 = 13. CH = 10 log2 10 + 13 log2 13 deoarece cele dou paranteze sunt un singur operand. n secvena:
a += b++ + c++; a*=--b - --c;

numrul operanzilor N2 = 6, iar numrul operatorilor N1 = 10, ceea ce conduce la complexitatea CH = 10 log2 10 + 6 log2 6
35

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Pentru programe de mari dimensiuni este preferabil s se utilizeze instrumente care numr operanzii, respectiv operatorii, permind automatizarea procesului de msurare a complexitii n sens Halstead.

2.4 Etapele ciclului de dezvoltare


Ciclul de via al unui produs software este, conform [MIHAL98], intervalul de timp de la momentul deciziei de realizare i pn la retragerea sau nlocuirea total a acestuia cu un produs software, reprezentnd orizontul de timp n care opereaz i evolueaz produsul program. Ciclul de dezvoltare este parte a ciclului de via al unui produs software i este definit ca totalitatea etapelor pe care le parcurge un produs software de la idee, pn la utilizarea lui de ctre beneficiar. Acest interval, mprit n general n faze, presupune definirea i analiza problemei, proiectarea produsului software, implementarea de cod, testarea i experimentarea acestuia, deci reprezint o parte a ciclului de via i anume cea care are ca scop dezvoltarea produsului. Ciclul de via adaug ciclului de dezvoltare etapa de utilizare, etapa de mentenan, precum i momentul scoaterii din uz, datorit uzurii morale a produsului software. Etapa de definire i analiz a problemei const n stabilirea informaiilor de intrare, a rezultatelor, a modelelor. Exist probleme bine definite, cnd pentru toate rezultatele exist modele i date iniiale suficiente. Problemele subdefinite fie nu au toate modelele definite, fie lipsesc datele iniiale. Problemele supradefinite conin fie modele complementare, fie mai multe date iniiale dect cer rezultatele. Definirea problemei conduce la elaborarea de specificaii ale cerinelor produsului, ce trebuie s fie complete, consistente i riguroase. Aceste cerine trebuie documentate i agreate cu clientul nainte de a trece la urmtoarea faz. Un document riguros de analiz cuprinde, pentru fiecare cerin funcional n parte, urmtoarele informaii: Intrrile; Ieirile; modelele datele de test; dimensiunile volumelor de date; precizia rezultatelor; condiii tehnice.
36

Ciclul de dezvoltare software

Etapa de proiectare const n elaborarea soluiei, corelnd cerinele care rezult din definirea problemei, cu resursele pe care le ofer limbajele de programare, tehnologiile software existente, precum i sistemele de gestiune a bazelor de date. Aceast faz asigur programatorului suficiente informaii pentru ca acesta s scrie rutine software care realizeaz aciuni bine definite n cadrul aplicaiei. Soluia elaborat este documentat i prezentat clientului spre aprobare. Ea se adreseaz urmtoarelor arii de interes n cadrul dezvoltrii produsului software: proiectarea interfeei cu utilizatorul, ce reprezint imaginea sistemului pentru utilizator; proiectarea bazei de date, prin care se stabilete cum vor fi stocate i structurate datele utilizate de produs; stabilirea aciunilor realizate de aplicaie sub aspectul datelor ce sunt prelucrate i a algoritmilor folosii pentru aceasta; identificarea i definirea interfeelor externe, prin care sistemul se conecteaz la alte sisteme existente (automat sau manual); stabilirea formatelor de fiiere folosite pentru exportul i importul de date; conversiile de date, ce se refer la posibilitatea ca, n cazul n care datele existente sunt ncrcate ntr-o aplicaie nou, anumite conversii i reformatri s fie necesare.

Pe lng cele menionate mai sus, designul unui produs software precizeaz arhitectura general a aplicaiei, modul n care modulele componente sunt combinate pentru a oferi funcionalitatea dorit, nivelul planificat pentru caracteristicile de calitate. Dac etapa de analiz a problemei spune ce trebuie s se fac, etapa de proiectare stabilete cum trebuie s se fac. Documentul de proiectare este folosit de programatori i de testeri, n etapele urmtoare, pentru a dezvolta produsul i pentru a testa dac funcionalitatea rezultat n urma codificrii corespunde funcionalitii proiectate. Etapa de implementare a codului const n scrierea efectiv a produsului software. Software trebuie scris ca s respecte cerinele specificate n faza de analiz i testate n timpul dezvoltrii. De regul exist standarde de programare i recomandri de soluii pentru problemele comune care sunt aplicate n timpul dezvoltrii produsului pentru a spori
37

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

calitatea acestuia. Principalele rezultate ale acestei faze sunt aplicaia n sine, documentaia i rezultatele testelor. Dintre activitile de asigurare i control al calitii, cele mai prezente n timpul acestei faze sunt cele de revizuire a codului surs i inspeciile de cod i de documente. Etapa de testare are ca obiectiv s stabileasc dac sistemul este robust din punct de vedere tehnic, fiabil i corespunde cerinelor pentru care a fost dezvoltat. Caracteristicile principale ale testrii sunt: posibilitatea de a identifica ulterior testele realizate; posibilitatea de a repeta execuia unui test; documentarea pailor urmai n testarea unei funcionaliti i a rezultatelor obinute. testarea fiecrei rutine software n parte; testare de integrare a modulelor asamblate n aplicaia final sau ntr-un subsistem; testare de sistem a ntregii aplicaii pe aceeai platform ca cea pe care clientul o va folosi; testele de instalare prin care se verific c procedurile i instruciunile de instalare sunt corecte; testele de regresie, realizate dup upgrade-uri de software (adugri de funcionalitate nou, corectri de defecte); teste de acceptan, care sunt parte din faza de instalare, i prin care clientul verific dac ceea ce i se livreaz corespunde cu ceea ce a cerut.

Exist cteva tipuri de testare, printre care:

Testarea reprezint o arie extrem de complex creia, de cele mai multe ori, i se acord insuficient atenie. Trebuie neles c orict de mult sar testa un produs, nu se poate garanta c aplicaia este complet lipsit de defecte. Costul testrii trebuie analizat prin prisma costului potenial al funcionrii proaste, prin prisma defectelor software. Pentru aplicaiile necritice, este acceptabil de exemplu, lansarea unei versiuni beta pentru ca utilizatorii s o testeze n producie. O astfel de abordare nu este acceptat n cazul sistemelor software critice.

38

Ciclul de dezvoltare software

Etapa de implementare reprezint predarea oficial a produsului mpreun cu documentele asociate clientului. Procesul efectiv de instalare presupune: instalarea software pe sistemele de calcul ale clientului; executarea testelor de acceptan mpreun cu clientul; semnarea unor documente prin care se accept produsul de ctre client; pregtirea viitorilor utilizatori ai sistemului pentru folosirea acestuia.

Etapa de mentenan, dei nu face parte din ciclul de dezvoltare software, este o etap extrem de important a ciclului de via, pe care nici o companie productoare de software nu trebuie s o neglijeze. Instalarea produsului i predarea lui ctre client nu nseamn c din acel moment, productorul software nu mai are nici o legtur cu produsul. Mentenana include urmtoarele activiti: rezolvarea problemelor care apar n timpul rulrii aplicaiei n mediul de producie detectarea, analiza i corectarea defectelor software; modificarea interfeelor determinat de adugri sau schimbri la platforma hardware pe care ruleaz software; extinderea funcionalitii sau mbuntirea performanelor clientul solicit modificri dup ce livrarea iniial i instalarea au fost realizate.

Perioada de mentenan care urmeaz imediat instalrii este inclus ca parte a unui contract de garanie furnizat de productorul software. Mentenana pe termen lung are un alt statut n cadrul relaiei client productor software. Pentru ca un proiect de dezvoltare s fie un succes, o abordare sistematic este necesar. Proiectul trebuie mprit n faze, fiecare cu un obiectiv clar. Munca efectuat n cadrul fiecrei faze furnizeaz dezvoltatorului informaii necesare pentru a estima efortul din faza urmtoare. Costul total al proiectului este, astfel, mai sczut dect estimarea realizat la nceputul proiectului. Nu toate proiectele urmeaz acest ciclu de dezvoltare. Dimensiunea proiectului, n termeni de cost i efort necesar, i natura proiectului
39

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

determin ce faze sunt relevante i ce efort suplimentar trebuie alocat pentru fiecare faz. Efectele pe care le genereaz un produs sunt multiplicate cu numrul de utilizatori simultani ai produsului. Este necesar ca activitatea de dezvoltare software s aib la baz procese de optimizare dinamic, adic de alegere din aproape n aproape a acelor resurse ce n final asigur realizarea de produse de foarte bun calitate.

40

3.1 Specificaiile de programare


Elaborarea de programe a depins i va depinde n continuare de resursele hardware i software existente la un moment dat. Elaborarea specificaiilor este un moment extrem de important n ciclul de elaborare a programelor. Specificaiile sunt ntr-un context mai larg, descrieri sistematice, riguroase a rezultatelor finale care trebuie obinute, a datelor iniiale i, respective, a formulelor de calcul. Specificaiile definesc cadrul n care se dezvolt un program, prin faciliti, restricii. Mult mai trziu au aprut problemele legate de grupurile int, de obinerea unor produse de nalt calitate. Elaborarea specificaiilor presupune un nivel de experien ridicat, o bun capacitate de analiz a proceselor i caliti de cuprindere a elementelor generale, n succesiunea lor logic. Dup ani lungi de experien n programare s-a pus problema elaborrii unor sisteme formalizate, neambigui pentru elaborarea de specificaii. Exist mari deosebiri ntre specificaiile necesare pentru o problem de calcule tiinifice i specificaiile pentru dezvoltarea de software pentru contabilitate, de exemplu. n primul caz, o formul sau un set de formule stabilesc riguros care sunt rezultatele i care sunt datele de intrare. n cazul problemelor economice, de exemplu, exist legi, regulamente, exist o experien acumulat, exist specialiti. Construirea modelelor de calcul, stabilirea rapoartelor finale i a datelor iniiale reprezint o art, specificaiile sunt produciile unor artiti. Dac de exemplu, trebuie soluionat o problem de statistic, n sensul calculului mediei aritmetice ponderate se definesc: datele de intrare: n numrul de grupe; fi frecvena de apariie a datelor din grupa i; xi nivelul grupei i pentru variabila x.
41

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

datele de ieire: xm nivelul mediei aritmetice. domeniile de variaie: n {5,6,....,1000} x i [1000;1000] f i [0;100] N x m [10000;10000]

formule de calcul:

xm =

f
i =1 n

* xi
i

f
i =1

Pentru a analiza calitatea specificaiilor se construiesc tabelele 3.1 i 3.2 n care sunt stabilite relaiile ntre elementele definite.
Dependena ntre variabila endogen i variabilele exogene

Tabelul 3.1
Variabila endogen Variabilele exogene
n fi xi * * *

xm

Utilizarea n formule a variabilelor

Tabelul 3.2
Variabile Formula xm n fi xi

xm =

f
i =1 n

* xi
i

f
i =1

42

Abordarea clasic

Avnd n vedere c n tabelele 3.1 i 3.2 nu exist linii sau coloane fr asteriscuri, rezult c definirile legturilor dintre date de intrare i rezultate sunt complete. Asteriscurile marcheaz prezena unei variabile n formul sau legtura dintre variabilele exogene i variabila endogen, aa cum rezult din formul. Specificaiile trateaz i cazurile de excepie. Pentru f1 = f2 = ..... = fn = 0, xm = 0. n specificaii sunt prezentate date de test, pentru seturile din tabelele 3.3, 3.4 i 3.5 i nivelurile variabilei xm.
Set de date identice

Tabelul 3.3
Nr. crt
1 2 ..... 15 xm = 10 10 10 10

fi
10 10 10

xi

Serii de date compensate simetric

Tabelul 3.4
Nr. crt
1 2 3 4 5 6 7 8 9 10 xm = 0 10 8 6 4 2 2 4 6 8 10

fi
-15 -13 -11 -9 -7 +7 +9 +11 +13 +15

xi

43

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Serii de date recursiv dependente

Tabelul 3.5
Nr. crt
1 2 3 4 1 3 5 7

fi = fi-1 + 2
3 11 19 27

xi = 4*fi - 1

Datele din tabele se construiesc aa fel nct s existe o formul de calcul pentru ele ca verificarea corectitudinii prelucrrilor realizate de program s fie mult mai uoar, ca n exemplul datelor din tabelul 3.6
Serii de date generate

Tabelul 3.6
Nr. crt
1 2 3 N 3 5 7 2*n + 1

fi = 2*i + 1
2 5 10

xi = i 2 + 1

n2 + 1

Aplicnd relaia:

xm =

f
i =1 n

* xi
i

f
i =1 n

pentru datele din tabelul 3.6 rezult:

xm =

(2i + 1)(i + 1)
i =1

(2i + 1)
i =1

dup efectuarea calculelor rezult:

xm =

n 2 + 6n + 8 3(n + 2)
44

Abordarea clasic

Se construiete o procedur care genereaz seriile fi, xi i calculeaz xm. Prin apelul programului de calcul pentru media aritmetic cu aceste date generate se obine un rezultat x`m. Dac x`m = xm, rezult c programul scris pentru calculul mediei aritmetice este corect n raport cu setul de date pentru care a fost testat. Specificaiile de programare sunt construcii care sistematizeaz informaii extrem de variate. Cei care elaboreaz specificaiile au rol hotrtor n definirea contextului prin restriciile asupra variabilelor, prin formulele construite i prin informaiile care nsoesc algoritmii de prelucrare. Absena unor restricii, definirea incorect a domeniilor, construirea de formule incomplete genereaz probleme serioase procesului de elaborare a programelor. n contextul actual sunt soluionate multe dintre problemele legate de elaborarea de specificaii. n contextul primelor abordri, n ceea ce privete scrierea de programe, programatorul era singurul care i definea datele de intrare, definea rezultatele i crea sau prelua algoritmi. Fr o gndire sistematic, fr instrumente adecvate, specificaiile includeau o serie de inexactiti sau eliminau o serie de aspecte, ceea ce reducea aria de cuprindere a programelor. Arta elaborrii de programe i avea izvorul n arta de a elabora specificaii.

3.2 Preluarea algoritmilor


Rezolvarea oricrei probleme are la baz un algoritm, dat fie printr-o formul, fie prin pai care descriu exact care sunt prelucrrile. Pentru o aceeai problem exist mai muli algoritmi. Trebuie ales acela care ndeplinete unul dintre criteriile: volumul de prelucrri este ct mai redus; volumul de prelucrri depinde de particularitile pe care le prezint datele de intrare; de exemplu, datele sortate cresctor deja trebuie s genereze un volum minim de prelucrri n cazul algoritmului de sortare cresctoare; numrul rezultatelor intermediare care trebuie stocate n memorie s fie ct mai redus pentru a asigura dimensiuni ct mai mari problemelor de rezolvat; volumul prelucrrilor s fie ct mai redus, cu accent pe scderea numrului de operaii de nmulire sau de mprire.
45

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Programatorii preiau algoritmii deja analizai din punct de vedere a calitii soluiei sau construiesc algoritmi proprii. Pentru verificarea unui ir x1, x2, ...., xn care are componentele ordonate cresctor se construiesc de ctre programator doi algoritmi: Algoritmul A1: pasul 1 : se iniializeaz variabila iv cu 0; pasul 2 : se traverseaz irul; pasul 3 : se compar xi cu xi+1; pasul 4 : dac xi > xi+1, se incrementeaz variabila iv; pasul 5 : dup ncheierea procesului de comparare se testeaz variabila iv; pasul 6 : dac iv = 0, se afieaz mesajul irul este ordonat, n caz contrar se afieaz mesajul irul nu este ordonat. pasul 1 : se traverseaz irul; pasul 2 : se compar xi cu xi+1; pasul 3 : dac xi > xi+1 se ntrerupe traversarea i se afieaz mesajul irul nu este ordonat; pasul 4 : dac traversarea se ncheie normal, se afieaz mesajul irul este ordonat.

Algoritmul A2:

Este important s se construiasc algoritmi complei i coreci pentru problemele de rezolvat i abia dup aceea s se urmreasc mbuntirea lor, fr a accepta conceptul de algoritm optim. Preluarea algoritmilor este o necesitate i modul concret prin care se realizeaz const n: asimilarea unei mulimi de algoritmi de baz, pentru operaii de prelucrare bine definite; alegerea algoritmilor care se potrivesc clasei de probleme n raport cu structurile de date utilizate; ntr-un fel sunt concepui algoritmii care lucreaz cu fiiere, altfel sunt construii algoritmii care opereaz pe masive; combinarea de algoritmi pentru a obine fluxurile de prelucrare specifice soluionrii unei probleme.
46

Abordarea clasic

Exist mai multe moduri de descriere a algoritmilor, dintre care sunt prezentate n continuare urmtoarele: forma text, n care operaiile i operanzii sunt dai sub form de fraze precum: se iniializeaz de la tastatura...; rnd pe rnd se adun fiecare element; se compar element cu element....; primul element se interschimb cu ultimul, al doilea se interschimb cu penultimul, procedeul continu n acelai fel pn cnd.... limbaj de descriere a operaiilor n succesiunea efecturii pseudo-cod : sau

x1 = 2 xi = xi-1, i = 2, 3, ...., n x1 = 0 x2 = 1 xi = xi

sau

+ xi-2, i = 2, 3, ....., n

dac xi > xi+1 interschimb xi cu xi+1

schemele logice, care reprezint o transcriere grafic a etapelor (pailor) unui algoritm.

Limbajul utilizat n descrierea algoritmului trebuie s conduc la elaborarea de programe, fr confuzii, care prin testare s evidenieze c pentru date de intrare complete i corecte se obine rezultatul corect indicat.

3.3 Elaborarea schemelor logice


Schema logic reprezint o modalitate uzual de reprezentare a algoritmilor folosind simboluri precum cele date n figura 3.1:

Figura 3.1 Simboluri pentru scheme logice

47

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

De asemenea, schemele logice includ conectori:

i arce orientate Nivelul de detaliere depinde de modul de nelegere a algoritmului, de rolul pe care l are cel care elaboreaz schema logic i persoana care elaboreaz textul surs. ntre schema logic i program trebuie s existe o coresponden clar n ceea ce privete numele variabilelor, etichetelor ntrebuinate i formulelor de calcul. Pentru aflarea elementului minim dintr-un ir i a poziiei acestuia se utilizeaz variabilele: n x[i] xmin pozmin i - numrul de componente al vectorului x[]; - componenta i a vectorului; - valoarea elementului minim; - poziia elementului minim; - variabil de control.

48

Abordarea clasic

Schema logic este dat n figura 3.2:

Figura 3.2 Schema logic pentru aflarea minimului i poziiei

49

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Pentru a verifica dac o matrice este simetric se construiete schema logic din figura 3.3.

Figura 3.3 Schema logic pentru verificarea simetriei unei matrice


50

Abordarea clasic

Pentru numrarea componentelor nule, negative i pozitive ale unui masiv a[m][n] bidimensional se elaboreaz schema logic din figura 3.4.
START

Citeste m,n
Citeste a[i][j], i=1, , m j=1,..,n

nrnul = 0 nrpoz = 0 nrneg = 0 i=0

e1

j=0

e2

a[i][j] > 0

Da

e3

nrpoz = nrpoz + 1

e5

a[i][j] < 0

Da

e4

nrneg = nrneg + 1

e5

nrnul = nrnul + 1

51

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Figura 3.4 Schema logic pentru numrarea elementelor negative, pozitive i nule

Schemele logice clasice corespund unui stadiu incipient al dezvoltrii limbajelor de programare. De exemplu, limbajul FORTRAN este nzestrat cu instruciunea IF cu sintaxa:
IF ( expresie ) e1, e2, e3

unde: e1 e2 e3 - eticheta instruciunii care se execut dac expresia este negativ; - eticheta instruciunii care se execut dac expresia este nul; - eticheta instruciunii care se execut dac expresia este pozitiv.

52

Abordarea clasic

O astfel de construcie impune utilizarea de instruciuni cu etichete i continuarea prelucrrii prin efectuarea unui salt necondiionat la secvena cu eticheta e4, figura 3.5.

Figura 3.5 Secvena cu salturi condiionate complete

53

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Pentru numrarea elementelor nule, pozitive i negative ale unui masiv bidimensional se construiete secvena de schem logic dat n figura 3.6.

Figura 3.6 Schem logic pentru scrierea de programe n limbajul FORTRAN


54

Abordarea clasic

Pe msur ce se dezvolt limbajele de programare, n schemele logice apar modificri. Programul scris n C++ dup schema logic din figura 3.4 este:
#include <stdio.h> #define M #define N 10 10

int main () { int i, j, m, n, a[M][N]; int nrplus, nrnegativ, nrnul; nrplus = nrnegativ = nrnul = 0; printf( "Introduce numarul de linii (<%d) = ", M ); scanf( "%d", &m ); printf( "Introduce numarul de coloane (%d) = ", N ); scanf( "%d", &n ); i = 0; et11: if ( i < m ) { j = 0; et12: if ( j < n ) { printf("a[%d][%d] = ", i, j ); scanf("%d", &a[i][j] ); j++; goto et12; } i++; goto et11; } i = 0; et1: if ( i < m ) { j = 0; et2: if ( j < n ) { if ( a[i][j] > 0 ) { nrplus++; } else { if ( a[i][j] < 0 ) { nrnegativ++; } else { nrnul++; } } j++; goto et2;

55

Analiza comparat a complexitii entitilor text generate prin tehnici de programare } i++; goto et1; } printf( "Numarul de elemente pozitive este %d\n", nrplus ); printf( "Numarul de elemente negative este %d\n", nrnegativ ); printf( "Numarul de elemente nule este %d\n", nrnul ); }

Datorit caracterului su artizanal, tehnica nu se baza pe reutilizarea codului. Programatorul rescria funcionaliti ce altfel se regseau n biblioteci scrise deja. Prin aceasta dimensiunea codului surs cretea foarte mult i odat cu ea i complexitatea software. De asemenea, frecvente erau i programele monolit, care conineau toat funcionalitatea n programul principal, neexistnd apeluri ctre subrutine. Pentru aplicarea formulei complexitii ciclomatice, se identific urmtoarele valori pentru parametrii acesteia: na nn = 36 = 31

Rezult c valoarea complexitii ciclomatice este: CM = 36 31 + 2 = 7 Valoarea obinut este relative mare, avnd n vedere c complexitatea problemei este mic, ns ea se datoreaz n special faptului c pe de o parte au fost folosite instruciuni de salt necondiionat, care au mrit numrul de arce din cadrul grafului asociat, dar i deoarece nici varianta de algoritm implementat nu este optim. Conform setului de valori-prag, acest program se ncadreaz n categoria de risc minim. Pentru aplicarea formulelor Halstead, se identific urmtoarele valori pentru parametrii acestora: n1 n2 = 5 = 8

N1 = 22 N2 = 36

56

Abordarea clasic

Pentru aceste valori, aplicnd formulele de calcul pentru metricile Halstead, se obine:
Metric
Lungimea programului Vocabularul programului Volumul Dificultatea Efort = = = = =

Valoare
64 14 384 14,25 5472

Dac se raporteaz valorile obinute la valorile-prag, se constat c ele se ncadreaz n intervalele acceptate. Trebuie menionat c, dei limbajul C++, folosit pentru a implementa rezolvrile la problema aleas, ofer implementri pentru structuri repetitive (for, while), s-a ales varianta cu instruciuni de salt necondiionat specific pentru perioada n care aceast tehnic de programare era folosit. Exist limbaje, cum este i cel de asamblare, care nu au implementri de structuri repetitive, i prin urmare ele trebuie scrise de ctre programator. Programarea clasic are o serie de imperfeciuni pe care programatorii de azi nu le accept sau pentru care au gsit soluii mai ales prin elaborarea de expresii condiionale compuse. Acum, pentru a verifica dac o matrice este sau nu simetric se scrie secvena:
. k = 1; for ( i = 0; i < m && k == 1; i++ ) { for ( j = 0; j < n && k == 1; j++ ) { if ( a[i][j] != a[j][i] ) k = 0; } } if ( k == 1 ) printf (matrice simetrica); else printf (matrice nesimetrica); .

Instruciunea if se nlocuiete cu expresia de atribuire:


k = a[i][j] == a[j][i].

secvena devenind:
k = 1; for ( i = 0; i < m && k == 1; i++ ) { for ( j = 0; j < n && k == 1; j++ ) { k = a[i][j] == a[j][i]; } } printf( k == 1 ? matrice simetrica : matrice nesimetrica); .

57

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Programarea clasic are un caracter direct, avnd de evaluat expresii simple i efectund prelucrri cu pai mruni, din aproape n aproape.

3.4 Scrierea programelor


i acum 40 de ani, ca i acum, programatorul scria programele n limbajele pentru care avea compilatoare, dimensiona probleme pentru resurse de memorie intern, proiecta fiiere nct s respecte restriciile de stocare pe suport intern sau extern. i atunci, ca i acum, au existat restricii. Datele i programele erau stocate pe benzi perforate, pe cartele, iar programatorii care au lucrat ntre 1985 1990 tiu c un loc la un terminal pentru a lucra interactiv era un lux, n timp ce n ziua de azi nu poate fi conceput n nici un chip dect lucru n reea, la un post de lucru. Cartelele perforate banda perforat, sunt azi piese de muzeu. i acum 30 40 de ani, programatorii, care erau selectai dintre cele mai inteligente persoane datorit restriciilor legate de resursa calculator, au avut de traversat aceleai etape ale ciclului de dezvoltare software. i atunci, ca i acum, existau mari probleme, existau preocupri de a le soluiona i chiar au existat produse software de foarte bun calitate pentru calcule economice, pentru optimizri, iar cine consider c problemele s-au dezvoltat odat cu posibilitatea pe care o dau monitoarele VGA, SVGA sau altele de ultim generaie, limiteaz rezultatele prin eliminarea unor soluii extreme de avansate obinute nc din anii 50. ntotdeauna au existat preocupri pentru programe foarte bune. Este cunoscut colecia de algoritmi i programe din biblioteca ACM, publicate i comentate n numerele mai vechi ale revistei Communications of ACM. i azi programatorii care urmresc adevrata performan, consult aceast colecie pentru a preleva rezultate dintre cele mai bune, tiut fiind c limbajul ALGOL a fost baz pentru tot ce este deosebit de avansat n programarea de azi. Dei, limbajele de programare limitau tipurile de date pentru tipurile fundamentale ntreg, real simpl precizie i real dubl precizie, orice problem avea o rezolvare prin : atribuirea de coduri numerice pentru iruri de caractere; utilizarea exclusiv bidimensionale. a masivelor unidimensionale sau

58

Abordarea clasic

Problema ordonrii ntreprinderilor dup cifra de afaceri, i corespunde azi textul surs:
#define N #define MAX_STRING int main() { int n, i, j, min; char* sc[N]; float cf[N]; memset(sc, 0, N); printf( "Introduce numarul de societati comerciale (<=%d)", N ); scanf( "%d", &n); for ( i = 0; i < n; i++ ) { sc[i] = (char*)malloc(MAX_STRING); printf("Numele firmei = "); scanf("%s", sc[i]); printf("Cifra de afaceri = "); scanf("%f", &cf[i]); 10 255

for ( i = 0; i < n - 1; i++ ) { min = i; for ( j = i+1; j < n; j++ ) { if ( cf[j] < cf[i] ) { min = j; } } //muta elementul minim pe pozitia i char* temp = sc[i]; sc[i] = sc[min]; sc[min] = temp; float f = cf[i]; cf[i] = cf[min]; cf[min] = f; } for ( i = 0; i < n; i++ ) { printf(" Societatea %s are CF %f\n", sc[i], cf[i]); } }

Programarea clasic soluiona problema prin codificarea ntreprinderilor i operarea cu doi vectori, unul de tip ntreg pentru codurile ntreprinderilor i unul de tip real pentru valorile cifrei de afaceri, obinnd
59

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

programul care, la acel moment, din cauza imposibilitii de a construi blocuri i datorit absenei instruciunii while, era scris folosind instruciunile if i goto care aveau menirea de a selecta situaiile diferite, cu efecte negative asupra fluenei ntregului demers. Se obine textul surs:
i = 0; et1: if ( i < n - 1 ) { min = i; j = i; et2: if ( j < n ) { if ( cf[j] < cf[i] ) { min = j; } j++; goto et2; } //interschimba pozitia i cu pozitia min int temp1 = sc[i]; sc[i] = sc[min]; sc[min] = temp1; float temp2 = cf[i]; cf[i] = cf[min]; cf[min] = temp2; i++; goto et1; } i = 0; et3: if ( i < n ) { printf(" Societatea %d are CF %f\n", sc[i], cf[i]); i++; goto et3; }

Comparnd textele surs, devine foarte clar necesitatea acceptrii faptului c evoluia coninutului unui program a depins strict de resursele care au fost la dispoziia programatorilor. Muli dintre programatorii cu prul alb sunt cei care au scris programe foarte bune n limbajul FORTRAN 4 acum 35 de ani, tot ei fiind cei care lucreaz n C# sau Java cu aceeai uurin.

60

Abordarea clasic

3.5 Testarea i implementarea programelor


Trebuie spus c n acele vremuri, utilizatorii calculatoarelor nu erau nici pe departe ceea ce sunt azi. Azi, ceteanul dispune de calculator, de internet. Acum 35 40 de ani, numai companiile importante achiziionau calculatoare. Existau analiti, programatori, iar operatorii din slile cu climatizare unde erau amplasate computerele de mrimea unor ifoniere, erau deja persoane foarte importante. Utilizatorii de software tiau s perforeze cartele de date, tiau s i depaneze programe. nseamn c programatorii rmneau n continuare alturi de produsele software pe care le realizau. Ceva mai trziu, programele aplicative au dezvoltat o relaie nou. Utilizatorul acestor programe trebuia s tie exact cum se dispun datele pe cartele pentru a stabili intrri complete i corecte. Bibliotecile de program includeau programe de clas A, testate sub toate aspectele, care nu mai produceau ntreruperi n execuie fr mesaje specifice. Programele de clas B erau testate suficient de bine, ns, nu erau excluse unele ntreruperi cu mesaje ale sistemului de operare. Programele de clas C erau deja programe despre care nu se ddeau aprecieri asupra comportamentului i asupra riscurilor de apariie a incidentelor de prelucrare. Se observ acum scderea interesului spre dezvoltarea de tehnici de testare probabil datorit existenei instrumentelor de asistare a procesului de elaborare a produselor software. Pentru testarea unui program se parcurg mai muli pai: se construiesc seturi de date de test pentru care se stabilesc rezultatele pe care programul le ofer; se preiau din literatur exemple rezolvate folosind att datele de intrare ale acestora, ct i rezultatele intermediare; se introduc n program instruciuni de afiare a rezultatelor intermediare; se introduc n program instruciuni care permit afiarea etichetelor instruciunilor care se execut.

De exemplu, programul pentru nsumarea elementelor unui ir se procedeaz astfel: se iniializeaz irul cu valorile 1,2, 3, .., n;
61

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

se afieaz valoarea variabilei de control a irului, valorile irului i sumele intermediare; se afieaz mesaje care arat c au fost parcurse etapele programului.

Pentru testare, programul are textul surs:


#define N 100 #define n 10 void main() { int i, x[N], suma; printf(Generare date de test); for (i = 0; i < n; i++) { x[i] = i; } printf(\n Intrare in procedura); suma = aduna(x, n); printf(\n Iesire din procedura); printf(\n suma = %d, suma); } int aduna(int x[], int n) { int suma = 0; for ( i = 0; i < n; i++ ) { suma += x[i]; printf(Suma dupa adunarea %d element cu valoarea %d este %d, i, x[i], suma); } printf(\n Gata); return suma; }

Pe monitorul computerului pentru n = 10, se afieaz:


Generare date de test Intrare in procedura 0 0 0 1 1 1 2 2 3 3 3 6 4 4 10 5 5 15 6 6 21 7 7 28 8 8 36 9 9 45 10 10 55 Gata Iesire din procedura Suma = 55
62

Abordarea clasic

Din analiza acestor informaii se verific faptul c programul efectueaz corect prelucrrile. n cazul n care se testeaz procedura:
int expresie( int a, int i, int k) { int result = 0; if ( i % 2 ) { if ( !(i % k) ) { printf("Numar divizibil cu %d\n", k); result = a * a; } else { printf("Numar nedivizibil cu %d\n", k); result = a; } } else { printf("Numar par\n"); result = a * a * a; } return result; }

pentru evaluarea expresiei:


a, dac i este impar e = a 2, dac i este numu impar diviyibil prin k a 3, n rest se introduce n programul principal i n procedur instruciuni care afieaz informaii despre fluxul de execuie al programului i din care s rezulte programul execut ceea ce trebuie i nu evaluarea unei alte expresii.
int expresie( int a, int i, int k) { int result = 0; if ( i % 2 ) { if ( !(i % k) ) { printf("Numar divizibil cu %d\n", k); result = a * a; } else { printf("Numar nedivizibil cu %d\n", k); result = a; } } else { printf("Numar par\n"); result = a * a * a; } return result; }

63

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

int main() { int a, i, k, n, j; printf( "Introduce numarul de seturi de date i = " ); scanf( "%d", &n ); printf( "Introduce numarul de variabile de control k = " ); scanf( "%d", &k );

printf("i\ti*i\ti*i*i\tk\ta\texpresie\n"); for ( j = 1; j <= k; j++ ) { for ( i = 0; i < n; i++ ) { printf("%d\t%d\t%d\t%d\t%d\t%d\n", i, i*i, i*i*i, j, i, expresie(i, i, j)); } } }

Pentru k = 7 i n = 10, secvena care se afieaz este:


i Numar 0 Numar 1 Numar 2 Numar 3 Numar 4 Numar 5 Numar 6 Numar 7 Numar 8 Numar 9 i*i i*i*i par 0 0 nedivizibil cu 7 1 1 par 4 8 nedivizibil cu 7 9 27 par 16 64 nedivizibil cu 7 25 125 par 36 216 divizibil cu 7 49 343 par 64 512 nedivizibil cu 7 81 729 k 7 7 7 7 7 7 7 7 7 7 a 0 1 2 3 4 5 6 7 8 9 expresie 0 1 8 3 64 5 216 49 512 9

Analiznd rezultatele intermediare, rezult c procedura efectueaz prelucrri corecte. Pentru programele cu grad de complexitate ridicat, procedurile de testare sunt mai elaborate. Cei care elaboreaz specificaiile aveau obligaia s furnizeze situaiile care trebuie testate, cu luarea n considerare a situaiilor care n practic ofereau cazuri greu de controlat,
64

Abordarea clasic

ateptndu-se ca prin implementarea produsului software, tocmai acele erori de prelucrare manual s fie nlturate.

3.6 ntre art, meteug i industrie


Activitatea de programare, prin faptul c era dezvoltat de persoane deosebit de inteligente i avea o pondere de peste 90% din costul produsului, a fost nconjurat de misterul creaiei artistice, nefcndu-se deosebiri radicale de modul n care se scriau programele i modul n care se realizau operele artistice. n plus, programul nu are o form material asemeni unui strung sau a unei statui. Nu ntmpltor, David E. Knuth i-a intitulat monumentala lucrare care st la baza activitii oricrui programator, ART OF PROGRAMMING. Programarea s-a nvat prin exemple, ca de la maestru la discipol. Numai dup apariia crilor de programare care au prezentat limbajele de programare folosind multe exemple s-au conturat unele direcii de baz. Programarea calculatoarelor a rmas o art att timp ct bibliotecile de subprograme nu au fost realiti cotidiene. De fiecare dat programatorul scria subprograme pe care deja le mai scrisese cndva de mai multe ori. n plus, nu a existat ncrederea n programele scrise de alii. Se justific aceast reinere prin: calitatea slab a programelor incluse n paginile crilor; contribuiile nefaste ale redactorilor de carte, crora ghilimelele li se preau c prin nlocuire cu apostrofuri dau frumusee textului, iar prin eliminarea slash-urilor(//) sau prin includerea pe toate liniile surs, se obine un aspect estetic acceptabil pentru carte; iar nlocuirea caracterului _ cu minus deja are efecte dintre cele mai compromitoare.

Trecerea spre meteug s-a impus cnd au trebuit scrise multe programe pentru a dezvolta sisteme informatice complexe. Deja exist un responsabil de proiect, deja trebuia s existe un mod de comunicare prin specificarea structurilor de articole, dimensiunilor de matrice. Trebuia pus ordine n modul n care sunt prelucrate datele pentru ca un program s nu distrug informaii pe care un alt program trebuie s le preia. Discuiile dintre analiti, discuiile dintre programatori au cristalizat tehnici de analiz i stiluri de programare.

65

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

A nceput perioada definirii unor reguli care s conduc la creterea calitii programelor. De la caracterul meteugresc spre caracterul industrial era doar un pas. Exagerrile legate de transferul mecanic a unor elemente de structur i de management din industria prelucrtoare spre producia de software a avut un singur efect: compromiterea ideii de industrie de software. Lucrurile apar acum cu totul sub alt lumin n contextul organizaiei virtuale de producie software pentru c: posturile de lucru sunt legate prin reea; accesul la resurse este dat de facilitile internetului; instrumentele de dezvoltare a aplicaiilor distribuite sunt o realitate; concepia dezvoltrii de aplicaii complete care s aduc acoperire avantajoas pentru cetean n planul fluxurilor materiale i a fluxurilor bneti este deja o realitate.

Aa cum societatea uman a trecut prin comuna primitiv, epoca bronzului, epoca fierului, prin sclavagism, feudalism, capitalism, comunism i retur, programarea calculatoarelor a reflectat salturile spectaculoase din domeniul hardware. n software nu exist penurie de idei. Exist numai restricii n plan tehnic. De la o etap la alta, pe msur ce barierele sunt doborte, se obin i salturi calitative n producia de software; iar ceea ce se ntmpl an de an este o evoluie normal i necesar care ajut dezvoltarea societii informaionale.

66

4.1 Reguli de construire


Acumularea experienei de ctre programatori a permis gruparea de subprograme n biblioteci. n primul rnd, programele de bibliotec sunt toate scrise ntr-un acelai limbaj de programare. n al doilea rnd, toate programele sunt regrupate astfel nct s conduc la rezolvarea de clase de probleme bine conturate. Bibliotecile matematice au programe de calcul polinomiale, de calcule matriceale, de rezolvare de sisteme de ecuaii i de implementare a algoritmilor analizei numerice pentru calcul diferenial. Bibliotecile statistice conin programe de analiz dispersional, de covarian, de regresie i de calcul a indicatorilor statistici. Bibliotecile de programe sunt astfel proiectate nct s permit lansarea n execuie a programelor, ct mai uor posibil. n al treilea rnd, programele de bibliotec au interfee prietenoase care asigur definirea problemelor de ctre utilizatori, introducerea de date i alegerea de opiuni n vederea obinerii rezultatelor dorite. n al patrulea rnd, bibliotecile de programe conin programe testate din toate punctele de vedere, nct s existe garania c acestea rezolv corect problemele. Pentru a dezvolta o bibliotec de programe se elaboreaz un plan riguros care include: obiectivul bibliotecii; limbajul de programare utilizat; algoritmii de prelucrare pentru care se elaboreaz programe; nivelul de testare al programelor; gradul de generalitate atins; precizia rezultatelor; dimensiunile problemelor de rezolvat; modul de tratare a erorilor.
67

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Regulile de construire a bibliotecilor de programe sunt stricte pentru a se obine programe de foarte bun calitate. Prima regul const n acceptarea unui stil de programare caracterizat prin: modul de alegere a numelor de variabile; modul n care sunt iniializate variabilele; construirea etichetelor i dispunerea lor, de exemplu, n ordine cresctoare e10, e20, ... , e300; utilizarea instruciunilor pentru a asigura un mod unitar de interpretare; astfel, dac se adopt un mod de parcurgere a unui masiv unidimensional cu ajutorul instruciunii for, atunci aceasta este aplicat n toate cazurile din cadrul programului, evitndu-se introducerea unor parcurgeri cu while sau chiar instruciuni de salt necondiionat, goto; separarea instruciunilor de citire i scriere de celelalte subprograme pentru a nu influena procesul de mentenan atunci cnd se dorete efectuarea de modificri n program, dar i pentru a obine creterea flexibilitii n ceea ce privete iniializarea variabilelor; stabilirea structurilor de date utilizate pentru a obine maximizarea gradului de utilizare a memoriei alocate; de la un program la altul, pentru aceleai prelucrri se folosesc aceleai structuri de date, denumirile lor nefiind diferite, mai ales, n ceea ce privete pointerii cu care se refer componentele; asigurarea continuitii att n ceea ce privete interfeele, ct i n ceea ce privete modul de elaborare a programelor. Biblioteca de programe trebuie s apar ca un ntreg, format din componente omogene programele.

Pe msur ce s-au impus bibliotecile de programe, dezvoltatorii de software au dezvoltat i biblioteci de subprograme, cele mai multe subprograme dezvoltnd funcii de prelucrare fundamentale n raport cu asigurarea calitii i mai ales cu creterea generalitii programelor. i subprogramele de bibliotec sunt elaborate pe baza unor reguli, din care mai importante sunt: construirea numelui de subprogram n aa fel nct s se rein cu uurin i s se intuiasc semnificaia prelucrrii; de exemplu, invmat() este subprogramul pentru inversarea de
68

Programarea standard

matrice, sortstring() este subprogramul pentru sortarea unui ir, sortfile() este subprogramul pentru sortarea unui fiier, prodpol() este subprogramul pentru produsul a dou polinoame; pentru tipul rezultatului returnat se indic de fiecare dat semnificaia; nivelul de autodocumentare este foarte ridicat, fiind incluse comentarii legate de semnificaia parametrilor, a secvenelor coninnd elemente de identificare a programatorului i a algoritmului utilizat; listele de parametrii au elemente comune care s fie uor interpretate i mai ales s fie uor de construit i de iniializat pentru a efectua un apel corect pentru fiecare subprogram; se stabilete regula privind modul de revenire n programul principal; ntr-un fel este privit programul ce conine o singur instruciune return, fa de programul care are mai multe instruciuni return.

eful de proiect al unei biblioteci de programe sau de subprograme, cnd constituie echipa de analiti i programatori prezint reguli, care sunt adoptate, chiar cu unele modificri. Dup ce regulile sunt adoptate, devin obligatorii i toate programele sau subprogramele sunt elaborate cu utilizarea acestor reguli. Prin respectarea regulilor, biblioteca de programe este o construcie unitar, operaional i, mai ales, care este utilizat de toi cei care dezvolt software, datorit economiei de efort pe care o genereaz.

4.2 Subprogramul
Programarea standard are la baz lucru cu subprograme performante, stocate n biblioteca de subprograme. Programatorul are menirea de a selecta cele mai potrivite subprograme pentru a soluiona fiecare problem n modul cel mai eficient. Pentru problema definit n capitolul Ciclul de dezvoltare software se consider o bibliotec de subprograme care opereaz cu masive unidimensionale. Regulile dup care se construiesc subprogramele sunt urmtoarele: numrul de componente ale irului este n; elementele irului sunt x[0], x[1], , x[n-1];
69

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

denumirea subprogramului arat operaia i operandul de baz; variabila i permite referirea elementelor unui ir sau refer liniile unui masiv bidimensional; variabila j refer elementele unei coloane din masivul bidimensional; masivul bidimensional este referit prin numele a[M][N].

Biblioteca de subprograme BVECTMAT se organizeaz pe dou niveluri: nivelul de baz conine proceduri de lucru cu masive unidimensionale (vectori); nivelul derivat conine proceduri de lucru cu masive bidimensionale vzute ca vectori de vectori, folosind subprogramele de lucru cu vectori.

Pentru copierea elementelor unei linii k dintr-un masiv bidimensional a[M][N] ntr-un masiv unidimensional x[N], se folosete subprogramul:
void copylinvect( int a[][N], int x[], int n, int k ) { for ( int j = 0; j < n; j++ ) { x[j] = a[k][j]; } }

Pentru copierea unei coloane k a matricei a[M][N] n vectorul x[M] se folosete subprogramul:
void copycolvect( int a[][N], int x[], int m, int k ) { for ( int i = 0; i < m; i++ ) { x[i] = a[i][k]; } }

Pentru nsumarea elementelor unui vector se folosete subprogramul:


int sumvect( int x[], int n ) { int sum = 0; for ( int i = 0; i < n; i++ ) { sum += x[i]; } return sum; }

70

Programarea standard

Pentru produsul scalar a vectorilor x[N], y[N] se definete subprogramul:


int prodscalar ( int x[], int y[], int n ) { int prod = 0; for ( int i = 0; i < n; i++ ) { prod += x[i] * y[i]; } return prod; }

Pentru copierea unui vector x[N] pe linia k a unei matrice a[M][N] se utilizeaz subprogramul:
void copyvectlin( int a[][N], int x[], int n, int k ) { for ( int j = 0; j < n; j++ ) { a[k][j] = x[j]; } }

Pentru copierea vectorului x[M] pe coloana k a matricei a[M][N] se folosete subprogramul:


void copyvectcol( int a[][N], int x[], int m, int k ) { for ( int i = 0; i < m; i++ ) { a[i][k] = x[i]; } }

Pentru numrarea elementelor unui ir x[] mai mari dect valoarea k, se folosete subprogramul:
int contorgreater ( int x[], int n, int k ) { int contor = 0; for ( int i = 0; i < n; i++ ) { if ( x[i] > k ) { contor++; } } return contor; }

71

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Pentru numrarea elementelor irului x[] egale cu o valoare k se utilizeaz subprogramul:


int contorequal ( int x[], int n, int k ) { int contor = 0; for ( int i = 0; i < n; i++ ) { if ( x[i] == k ) { contor++; } } return contor; }

Pentru a contoriza elementele irului mai mici dect o valoare k, se scrie subprogramul:
int contorless ( int x[], int n, int k ) { int contor = 0; for ( int i = 0; i < n; i++ ) { if ( x[i] < k ) { contor++; } } return contor; }

Iniializarea prin atribuire a elementelor vectorului x[] cu o valoare k se realizeaz prin procedura:
void initvect ( int x[], int n, int k ) { for ( int i = 0; i < n; i ++ ) { x[i] = k; } }

Pentru iniializarea componentei de pe poziia poz a irului x[] cu o valoare k se utilizeaz procedura:
void initpoz ( int x[], int poz, int k ) { x[poz] = k; }

Pentru realizarea procedurilor derivate se utilizeaz procedeul de lucru cu masive unidimensionale. Astfel, generarea matricei unitate linie de linie presupune conturarea unei structuri repetitive de tip for dat n figura 4.1.
72

Programarea standard

void genunit ( int a[][N], int m, int n ) {


int i, j; for ( i = 0; i < m; i++ ) {

} }

Figura 4.1 Funcia de generare a matricei unitate folosind funcii de lucru cu vectori

Procedura complet are textul surs:


void genunit (int a[][N], int m, int n ) { int x[N]; for ( int i = 0; i < m; i++ ) { initvect(x, n, 0); initpoz(x, i, 1); copyvectlin(a, x, m , n, i); } }

Subprogramul pentru scderea a dou matrice este:


void scadmat(int a[][N], int b[][N], int m, int n) { int i, x[N], y[N], z[N]; for ( i = 0; i < m; i++ ) { copylinvect(a, x, m, n, i); copylinvect(b, y, m, n, i); scadvect(x, y, z, n); copyvectlin(a, z, m, n, i); } }

73

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Subprogramul scadvect() care evalueaz expresiile z[i] = x[i] y[i], are textul surs:
void scadvect(int x[], int y[], int z[], int n) { int i; for ( i = 0; i < n; i++ ) { z[i] = x[i] - y[i]; } }

Pentru operaia de adunare a dou matrice a i b cu rezultat n matricea c, se construiete subprogramul:


void adunmat( int a[][N], int b[][N], int m, int n) { int i, x[N], y[N], z[N]; for ( i = 0; i < m; i++ ) { copylinvect(a, x, m, n, i); copylinvect(b, y, m, n, i); adunvect(x, y, z, n); copyvectlin(a, z, m, n, i); } }

Subprogramul adunvect() care evalueaz expresiile z[i] = x[i] + y[i], are textul surs:
void adunvect(int x[], int y[], int z[], int n) { for ( int i = 0; i < n; i++ ) { z[i] = x[i] + y[i]; } }

Dac trebuie scris subprogramul pentru transpunerea unei matrice a[][N], obinndu-se matricea b[][M], procedura corespunztoare este:
void transpune ( int a[][N], int b[][N], int m, int n) { int j; int x[N]; for ( j = 0; j < n; j++ ) { copycolvect(a, x, m, j); copyvectlin(b, x, m, j); } }

74

Programarea standard

Pentru produsul a dou matrice se scrie procedura:


void prodmat( int a[][N], int b[][P], int c[][P], int m, int n, int p) { int i, j; int x[N], y[N]; for ( i = 0; i < m; i++ ) { copylinvect(a, x, n, i); for ( j = 0; j < n; j++ ) { copycolvect(b, y, n, j); c[i][j] = prodscalar(x, y, n); } } }

Iniializrii de la tastatur a elementelor vectorului x[N] i corespunde procedura:


void citvect (int x[], int n) { for ( int i = 0; i < n; i++ ) { printf("x[%d] = ", i); scanf("%d", &x[i]); } }

Pentru afiarea elementelor unui ir se scrie procedura:


void scrievect (int x[], int n) { for ( int i = 0; i < n; i++ ) { printf("x[%d] = %d", i, x[i]); } }

Iniializarea unei matrice de la tastatur linie de linie se efectueaz prin procedura:


void citmat(int a[][N], int m, int n) { int i, x[N]; for ( i = 0; i < m; i++ ) { citvect(x, n); copyvectlin(a, x, n, i); } }

75

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Procedura pentru numrarea elementelor pozitive, nule respectiv negative ale unei matrice se realizeaz cu ajutorul procedurilor:
int contorplus (int a[][N], int m, int n) { int i, x[N]; int contor = 0; for ( i = 0; i < m; i++ ) { copylinvect(a, x, n, i); contor += contorgreater(x, n, 0); } return contor; }

int contorminus (int a[][N], int m, int n) { int i, x[N]; int contor = 0; for ( i = 0; i < m; i++ ) { copylinvect(a, x, n, i); contor += contorless(x, n, 0); } return contor; } int contorzero (int a[][N], int m, int n) { int i, x[N]; int contor = 0; for ( i = 0; i < m; i++ ) { copylinvect(a, x, n, i); contor += contorequal(x, n, 0); } return contor; }

Pentru rezolvarea problemei PROB formulate n capitolul Ciclul de dezvoltare software, programul apelator va conine: apelul subprogramului citmat() pentru iniializarea de la tastatur; apelul subprogramului contorplus() elemente mai mari dect k = 0; pentru contorizare

apelul subprogramului contorzero() pentru numrare elemente egale cu 0;

76

Programarea standard

apelul subprogramului contorminus() elementelor mai mici dect k = 0;

pentru

numrarea

apelul unui subprogram pentru afiarea valorilor nrplus, nrminus i nrzero cum este urmtoarea:

void printint (char w[], int x) { printf(" %s %d\n", w, x); }

Se observ c programul apelator conine exclusiv definiri de operanzi i apeluri de funcii.


int main() { int a[M][N]; int m, n; int nrplus, nrminus, nrnul; printf("Introduce numarul de linii = "); scanf("%d", &m); printf("Introduce numarul de coloane = "); scanf("%d", &n); citmat(a, m, n); nrplus = contorplus(a, m , n); nrminus = contorminus(a, m, n); nrnul = contorzero(a, m, n); printint("Numarul de elemente pozitive este ", nrplus); printint("Numarul de elemente negative este ", nrminus); printint("Numarul de elemente zero este ", nrnul); return 1; }

Pentru aplicarea formulei complexitii ciclomatice pentru programul apelator (funcia main) se identific urmtoarele valori pentru parametri: na nn = 11 = 12

Rezult c valoarea complexitii ciclomatice este: CM = 11 12 + 2 = 1

77

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

O astfel de valoare are mai multe semnificaii: datorit atomicizrii aciunilor, i gruprii lor n biblioteci de programe i subprograme, construirea unui produs software este mult simplificat, ajungndu-se la situaia ideal de a avea de scris doar o succesiune de apeluri de rutine pentru implementarea unei funcionaliti; din acest punct de vedere complexitatea produsului este redus, mai ales n condiiile unei bune documentri a rutinelor folosite; dac bibliotecile sunt concepute n cadrul aceluiai proiect ca i produsul software, atunci valoarea complexitii este neltoare, pentru c ea nu exprim i complexitatea ascuns a rutinelor folosite. n cazul n care se calculeaz i complexitile ciclomatice ale rutinelor apelate din cadrul programului apelator, se obin urmtoarele rezultate pentru parametrii formulei i respectiv pentru complexitate: Rutin
main citmat contorplus contorminus contorzero printint

na
11 5 7 7 7 0

nn
12 4 6 6 6 1

Complexitate
1 3 3 3 3 1

Complexitatea total este 14, cu urmtoarele ipoteze: instruciunea for este considerat o singur instruciune i nu trei; nu s-a mers mai departe de primul nivel de derivare, adic nu a fost dimensionat i complexitatea rutinelor de pe nivelul de baz al bibliotecii de subprograme. Se observ, doar n condiiile n care se iau n considerare i complexitile rutinelor apelate, valoarea complexitii ciclomatice totale se apropie de valoare obinut pentru abordarea clasic. ns, n mod firesc, are sens calculul complexitii doar pe baza codului din programul apelator, fie i din simplul motiv c biblioteca de subprograme este deja compilat i prin urmare nu exist un acces la codul-surs.

78

Programarea standard

n condiiile n care se consider semnificativ, analiza doar asupra programului apelator, pentru aplicarea formulelor Halstead se identific urmtoarele valori pentru parametrii: n1 n2 N1 N2 = = = = 2 6 5 20

Numrul total de operanzi este semnificativ mai mare dect celelalte valori datorit utilizrii unora dintre acetia n apeluri repetate ctre subrutine pentru a implementa funcionaliti distincte. Valorile pentru metricile Halstead, n aceste condiii sunt: Metric
Lungimea programului Vocabularul programului Volumul Dificultatea Efort = = = = =

Valoare
25 8 25*log28 3,3 75,75*log28

Comparativ cu valorile obinute pentru abordarea clasic, acestea sunt mult inferioare, ceea ce dovedete o mai bun implementare a rezolvrii problemei, cu o complexitate i un efort mult diminuat prin reutilizarea subrutinelor din biblioteca de subprograme. Programarea standard se caracterizeaz, n principal, printr-o productivitate mult crescut.

4.3 Generalitatea subprogramelor


Programarea standard impune dezvoltarea de subprograme cu un grad de generalitate foarte ridicat. n primul rnd, subprogramele trebuie s acopere o arie mai ridicat a problemelor. De exemplu, pentru calculul mediei, se impune a abordare gradat. Mai nti se construiete procedura pentru calculul mediei aritmetice simple, cu textul surs:
float mediaaritm( float x[], int n) { int i; float xmed = 0; for ( i = 0; i < n; i++ ) { xmed += x[i]; } xmed /= n; return xmed; }

79

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Dup aceea se construiete procedura pentru calculul mediei aritmetice ponderate, cu textul surs:
float mediapond ( float x[], int f[], int n) { int i, sumf = 0; float sumxf = 0, xmed; for ( i = 0; i < n; i++ ) { sumf += f[i]; sumxf += x[i] * f[i]; } xmed = sumxf / sumf; return xmed; }

Dac se dorete creterea generalitii unui subprogram n sensul c acesta s permit fie calculul mediei aritmetice simple, fie calculul mediei aritmetice ponderate, se procedeaz la elaborarea textului surs:
float media ( float x[], int f[], int n, int k) { int i, sumf = 0; float sumxf = 0, xmed; if ( k == 0 ) { for ( i = 0; i < n; i++ ) { f[i] = 1; } } xmed = mediapond(x, f, n); return xmed; }

Utilizatorul iniializeaz variabila k pe zero dac dorete s calculeze o medie aritmetic simpl. Pentru a calcula media aritmetic ponderat variabila k se iniializeaz cu o valoare diferit de zero. Mai mult, dac se dorete calculul altor tipuri de medii (media geometric, media armonic) n acelai subprogram, se impune efectuarea de modificri adecvate. n al doilea rnd, generalitatea trebuie privit prin prisma acceptrii cazurilor particulare. Trebuie tratate distinct cazurile particulare. De exemplu, subprogramul care trateaz situaia n care suma frecvenelor din relaia este nul.
x=

x
i =1 n i =1

fi
i

80

Programarea standard

Textul surs al subprogramului mediapond() este:


float mediapond ( float x[], int f[], int n ) { ..... if ( sumf == 0 ) { xmed = 0; }else { xmed = sumxf / sumf;

} ...............
}

Proiectantul bibliotecii trebuie s stabileasc outputurile subprogramelor pentru situaiile particulare; de cele mai multe ori subprogramul returneaz coduri asociate poziiilor unei liste de mesaje care trebuie afiate. Codurile trebuie testate pentru a determina fluxuri de prelucrare difereniate funcie de outputurile subprogramelor. n al treilea rnd, subprogramele conin teste suficient de puternice pentru a permite efectuarea de calcule. Expresia:
x=
n

x
i =1 n i =1

fi
i

pentru a fi evaluat corect trebuie ca fi >= 0, i = 1, 2, ..., n i n > 0. Aceste condiii trebuie avute n vedere de designerii de subprograme. Se ia n considerare atitudinea acestora fie de a lsa programatorul care dezvolt aplicaii folosind subprograme de bibliotec pentru a face validrile, fie de a le ncorpora n subprograme i de a furniza mesaje referitoare la modul n care s-a derulat prelucrarea. Astfel, se d subprogramul:
int mediapondt ( float x[], int f[], int n, float &xmed ) { int rezultat = 0; if ( n < 1 ) { rezultat = -1; } if ( contorless (f, n, 0) ) { rezultat = -2; }

81

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

if ( rezultat == 0 ) { xmed = mediapond( x, f, n); } return rezultat; }

Subprogramul returneaz 0 dac prelucrarea s-a efectuat complet i corect. Subprogramul returneaz -2 dac exist frecvene negative i returneaz -1 dac numrul de componente ale irului nu conine cel puin un element. n al patrulea rnd, generalitatea problemei crete atunci cnd subprogramele sunt construite pentru a accepta diferite tipuri de operanzi. Pentru produsul scalar a doi vectori de tip ntreg, se construiete subprogramul:
long int prodscalar( int x[], int y[], int n) { long int rezultat = 0; for ( int i = 0; i < n ; i++ ) { rezultat += x[i] * y[i]; } return rezultat; }

Pentru produsul scalar a doi vectori de tip float se construiete:


float prodscalar( float x[], float y[], int n) { float rezultat = 0; for ( int i = 0; i < n ; i++ ) { rezultat += x[i] * y[i]; } return rezultat; }

n programarea orientat obiect aceast problem de multiplicare a codului funcie de tipul operanzilor este soluionat folosind descriptorul template. Biblioteca de subprograme este construit sub form de componente interdependente. Dac se dorete soluionarea unei probleme, mai nti se analizeaz dac exist deja subprogram n bibliotec. n caz contrar, se identific subprogramele apte s rezolve problemele fiecrui pas al algoritmului. Dac acest aspect impune dezvoltarea de subprograme de
82

Programarea standard

baz, evident, acestea se elaboreaz. Din aproape n aproape se dezvolt o bibliotec de subprograme care, n al cincilea rnd, acoper prin diversitatea de prelucrri de baz, toate cerinele pentru a soluiona orice problem, generalitatea bibliotecii fiind apreciat n raport cu diversitatea de probleme.

4.4 Listele de parametrii


Cnd se elaboreaz o bibliotec de subprograme, trebuie respectate o serie de reguli, care ncep cu lista de parametrii, continu cu stilul de programare i se ncheie cu modul n care este testat fiecare component a bibliotecii. Lista de parametrii, aa cum arat experiena multor ani de programare, este alctuit din trei liste i anume: lista parametrilor ce corespund datelor de intrare; aceti parametrii apar n membrul drept al unei expresii aritmetice; este indicat s nu se opereze modificri asupra acestor variabile pentru a nu schimba premisele altor subprograme care au nevoie de acele variabile cu valorile lor iniiale; lista rezultatelor, conine numele parametrilor care apar n membrul stng al unei expresii de atribuire; lista variabilelor de stare care conin coduri ce privesc cazurile de excepie, codurile mesajelor de eroare care vor fi afiate; se construiete o list de coduri care se asociaz unei variabile de stare, n toate subprogramele fiind atribuite numai valori n lista de coduri; de exemplu, variabila ik este o variabil de stare; valorile pe care le ia aceasta sunt date n tabelul 4.1. Valori asociate strilor unui subprogram Tabelul 4.1 Valoare
0 1 -1 -2 -3 2 3 4

Semnificaie
Prelucrare complet care a condus la rezultate corecte ntreruperea prelucrrilor nainte de a efectua o mprire la zero Un masiv are numr de componente negativ O variabil are valori n afara unui interval impus Argumentul unui logaritm sau al unui radical este negativ Parametrul are o valoare n afara elementelor enumerate Numele fiierului este necunoscut Elementul cu cheia specificat nu exist
83

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Dac toate subprogramele sunt nzestrate cu variabila de stare ik n lista de parametrii, n programul apelator sau n subprograme se introduce o secven de program obligatorie de testare a ei. Continuarea prelucrrii se realizeaz dac i numai dac, variabila ik are la ieirea din procedur valoarea zero, aa cum se arat n figura 4.2.

Figura 4.2 Flux cu testarea variabilei de stare

84

Programarea standard

Listele de parametrii pentru subprogramele dintr-o bibliotec sunt extrase dintr-o list comun de nume, utilizatorii bibliotecii trebuind obligatoriu s cunoasc aceast list comun de nume. Mai mult, pentru subprograme care au prelucrri ce se refer la aceleai variabile, se impune ca listele de parametrii s fie identice. De exemplu, n tabelul 4.2 sunt date proceduri care au liste de parametrii identice ca structur i ca poziie a elementelor i ca nume pentru parametri. Proceduri cu liste identice de parametri Tabelul 4.2 Prototipul procedurii addmat (a, b, m, n, c) scadmat (a, b, m, n, c) prodmat (a, b, m, n, c) compartmat (a, b, m, n, c) Semnificaia adun matricele a, b, rezultatul este matricea c evalueaz expresia c = a b, unde a, b, c sunt matrice cu m linii i n coloane calculeaz elementele unei matrice c dup relaia cij = aij * bij compar elementele a dou matrice cij = 0 dac aij = bij cij = 1 dac aij > bij cij = -1 dac aij < bij Programarea standard i dovedete eficiena dac subprogramele sunt bine construite, avnd un grad de omogenitate maxim, nct programatorii s se recunoasc pe ei nii prin nivelul ridicat al performanei ncorporate n secvenele de texte surs. n cazul n care un programator identific secvene care prin nlocuirea cu altele mult mai performante schimb calitatea unei proceduri, ncrederea n bibliotec scade, programarea standard fiind periclitat.

4.5 Programul principal, programul apelator


Dorina oricrui programator este maximizarea gradului de reutilizare de componente. Programarea standard are ca obiectiv elaborarea de biblioteci de subprograme care s asigure maximizarea gradului de

85

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

reutilizare. Este important s fie cunoscute att bibliotecile, ct i componentele lor, adic subprogramele incluse n ele. Dac exist o problem P de rezolvat, n faza de analiz se stabilesc datele de intrare DI1, DI2, ...., DIn i rezultatele care trebuie obinute RI1, RI2, ...., RIm. n funcie de volum, de tip, de modul de regrupare, datele de intrare i rezultatele sunt puse n coresponden cu unele dintre structurile de date cunoscute. Rezult automat tipologia de probleme n raport cu operanzii de prelucrat. Dac sunt luate n considerare urmtoarele structuri de date: VE M1 M2 FS LS LD ST AB GR BB MR - variabile elementare - masiv unidimensional - masiv bidimensional - fiier secvenial - list simpl - list dubl - stiv - arbore binar - graf - arbore B - matrice rar

modulele sau subprogramele, n faza de proiectare sunt cu un grad de omogenitate ridicat, n primul rnd, dac includ operanzi de acelai tip, n proporie covritoare. De exemplu, n figura 4.3 e dat o structur de program apelator care include apel de subprograme cu grad maxim de omogenitate a structurilor de date utilizate.

86

Programarea standard FS LS Conversie() Calcul3() LS LS Calcul1() Calcul4() LS LS Calcul2() Conversie() FS

Figura 4.3 Program apelator omogen din punct de vedere al structurilor de date

Stabilirea structurilor de date din lista de parametrii ai subprogramului determin care este biblioteca utilizabil, care sunt subprogramele care se reutilizeaz de ctre programator pentru a-i soluiona problema. Problema P se descompune n subproblemele P1, P2, ....., Pr. Problemei P i va corespunde programul apelator PA, figura 4.4. Fiecrei subprobleme i corespunde apelarea unui subprogram SP1(), SP2(), ...SPk(). Descompunerea subproblemei Pi n alte subprobleme Pi1, Pi2, ....., Piki impune includerea n subprogramul SPi() a apelurilor de subprograme SPi1(), SPi2(), ....SPiki(). Programarea standard impune ca structura arborescent s includ un numr de niveluri rezonabil, iar frunzele arborescenei sunt componente ale unei biblioteci de subprograme. Rezult c programatorul care stpnete programarea standard, trebuie s dezvolte o structur arborescent, trebuie s tie care sunt componentele bibliotecii, tehnologia bottom-up fiind cea mai nimerit de a construi soluia ca program a problemei. Astfel, pentru o problem P dat n figura 4.4 se construiete programul dat n figura 4.5.

87

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Figura 4.4 Structura problemei P


void main() { p_1(); p_2(); p_3(); } p_1() { p_1_1(); p_1_2(); p_1_3(); } p_2() { p_2_1(); p_2_2(); p_2_3(); p_2_4(); } p_3() { p_3_1(); p_3_2(); p_3_3(); }

Figura 4.5 Program asociat structurii arborescente P

Toate componentele de pe nivelul al doilea sunt subprograme de bibliotec. Programarea standard este programarea reutilizrii de subprograme. Activitatea de programare este reorientat spre a dezvolta subprograme reutilizabile, iar comunicarea ntre programatori este esenial. n momentul n care activitatea unui programator este analizat calculnd raportul dintre secvenele originale de instruciuni i lungimea programului, toat problematica efortului de programare, se rezolv de la sine. Secvenele originale se obin dintr-un program, dup ce se elimin toate secvenele pentru care exist subprograme de bibliotec. La un moment dat, programarea standard s-a constituit n factor progres, impunnd o component de baz n ingineria software, partea dedicat reutilizrii de subprograme.
88

5.1 Reguli de baz


Programarea structurat, conform [MIHAL83], const dintr-o mulime de restricii i reguli de programare pe care programatorul trebuie s le respecte, n acest fel, eliminndu-se muli dintre factorii care conduc la erori i care complic problemele de testare i de ntreinere. Se identific trei structuri de control i anume: structura liniar: se consider instruciunile I1, I2, ..., Iin care se execut una dup cealalt aa cum arat arcele orientate din figura 5.1:

Figura 5.1 Structur liniar

ntr-un program, structura liniar apare sub forma unor instruciuni dispuse una dup cealalt; de exemplu secvena:
s = 0; i++; s = x[i] + x[i] * x[i];

formeaz o structur liniar; structura alternativ, care presupune o expresie condiional C1 i dou secvene S1 i S2; dac, dup evaluarea expresiei condiionale C1, se obine valoarea logic adevrat, se execut secvena S1, n caz contrar se execut secvena S2, figura 5.2:

89

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Figura 5.2 Structur alternativ

De exemplu, pentru evaluarea expresiei


2 2 a + b , daca a > b e= 2 a + b 3 , daca a b

se realizeaz schema logic din figura 5.3:

Figura 5.3 Structur alternativ pentru evaluarea expresiei E

90

Abordarea structurat

structura repetitiv sau de ciclare, care presupune o expresie condiional C i o secven S de program care se execut de un numr finit de ori, pn cnd condiia i schimb valoarea. O astfel de structur are una din formele: repetitiv cu test iniial, n care secvena S se repet atta timp ct condiia C este adevrat, apoi se execut secvena S`;

Figura 5.4 Structur repetitiv cu test iniial

repetitiv cu test final, n care se execut secvena S, pn cnd condiia C devine adevrat, apoi se execut secvena S`;

Figura 5.5 Structur repetitiv cu test final

repetitiv cu contor, care presupune existena unei variabile de control i, a unei valori iniiale a acesteia, vinit, a unei valori finale vfin si a unei raii r, precum i o secven S care se execut, iar variabilele incluse n ea depind de variabila de control i; schema logic corespunztoare este prezentat n figura 5.6;
91

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Figura 5.6 Structur de control avnd repetri contorizate

Pentru problema de determinare a numrului de elemente pozitive, negative i respectiv nule dintr-o matrice, prezentat n capitolul al doilea, schema logic corespunztoare utilizrii n exclusivitate a celor trei tipuri de structuri este dat n figura 5.7.

92

Abordarea structurat

Figura 5.7 Schema logic pentru numrarea elementelor negative, pozitive i nule

Programarea structurat determin o ordonare a dezvoltrii succesiunii operaiilor, obligndu-i pe programatori s realizeze construcii ct mai clare.

93

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

5.2 Programarea fr GOTO


Introducerea n limbajele de programare a instruciunii GOTO are menirea de a dezvolta programe cu arce orientate care se ntretaie, figura 5.8.

Figura 5.8 Graf asociat unui program cu salturi napoi (A), cu salturi nainte (B) i cu salturi napoi i nainte (C) ntretiate

O utilizare frecvent a salturilor necondiionate este pentru implementarea structurilor repetitive, n lipsa unor construcii oferite de limbajul de programare. De asemenea, o alt utilizare apare n situaia n care se dorete creterea vitezei de execuie. Secvenele de cod cu salturi necondiionate sunt mai rapide, ns mai greu controlabile sub aspectul fluxului de execuie. Limbajele de nivel nalt doar includ printre cuvintele lor rezervate aceast instruciune, ns nu furnizeaz nici o implementare. Salturile necondiionate rmn apanajul limbajelor de asamblare i ale limbajelor de nivel mediu (C/C++), ns i la acestea din urm, utilizarea lor nu este recomandat, preferndu-se abordrile structurate. Programarea structurat este o tehnic n care programatorul nu trebuie s foloseasc instruciunea de salt GOTO. Cele trei tipuri fundamentale de structuri permit implementarea acestei cerine. Dac se consider limbajul de asamblare i se analizeaz procesul de compilare, se observ c instruciunea de salt necondiionat jmp este inevitabil.

94

Abordarea structurat

Structurii alternative din figura 5.2 i se asociaz secvena din figura 5.9.

Figura 5.9 Construcia secvenial asociat structurii alternative pentru limbajul de asamblare

Implementarea unei structuri alternative presupune operaii anterioare testrii indicatorilor de condiie, iar n cazul unui rezultat negativ al evalurii se execut un salt necondiionat la secvena ce trebuie executat n acest caz (corespondentul ntr-un limbaj de programare evoluat este varianta else a structurii if). i n cazul structurii repetitive, instruciunea jmp este inevitabil, figura 5.10.

95

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Figura 5.10 Construcie secvenial asociat structurii repetitive pentru limbajul de asamblare

Limbajele de programare evoluate includ apeluri de funcii de bibliotec. De exemplu, n programul din figura 5.11, programul principal PROG1 apeleaz subprogramele calcul1, calcul2 i calcul3.

96

Abordarea structurat

Figura 5.11 Instruciuni de salt necondiionat la apeluri i reveniri la lucru cu subprograme

Instruciunile call i ret conin i salturi necondiionate care definesc modificri ale registrului IP cu valori mai mari de 6 baii. Rezult c programarea fr GOTO este un deziderat i limbajele evoluate reuesc s mascheze apariiile de baz ale salturilor necondiionate.

5.3 Conversii de programe


Din punct de vedere al teoremei de structur, a lui Bhm-Jacopini, un program structurat este unul care are numai structuri de tip secvenial, ifthen-else i repetitive condiionate anterior. Variantele de structuri de tip ifthen sau repetitive condiionate posterior trebuie transformate n structurile menionate anterior, numite i structuri fundamentale. Principala metod de transformare o constituie duplicarea de cod. De exemplu, se consider structura if-then urmtoare:

97

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Figura 5.12 Structur alternativ de tip if-then

Pentru a o transforma ntr-o structur n care s se regseasc doar structuri fundamentale, se duplic codul, obinndu-se urmtoarea schem:

Figura 5.13 Structur if-then rescris folosind doar structuri fundamentale

n practic ns nu se opteaz pentru scrierea structurii de tip if-then folosind doar structuri fundamentale, pentru c, aa cum se observ n figur, cantitatea de cod duplicat este semnificativ, iar introducerea unei
98

Abordarea structurat

noi testri a condiiei C1 pe lng faptul c afecteaz performana codului (este tiut faptul c operaiile de comparare sunt costisitoare, din punct de vedere ale procesorului), afecteaz i lizibilitatea algoritmului. n cazul structurii repetitive condiionate posterior, se realizeaz tot o duplicare de cod, ns impactul asupra performanei i lizibilitii codului este mult mai mic. Considerndu-se schema din figura 5.5, ea se rescrie folosind doar structuri fundamentale n figura 5.14:

Figura 5.14 Structura repetitiv rescris folosind doar structuri fundamentale

Se observ c se duplic doar blocul funcional S, ceea ce nu afecteaz deloc performana codului i ntr-o msur foarte mic lizibilitatea lui. Probleme sunt atunci cnd blocul S trebuie modificat, fiindc modificarea trebuie realizat n dou locuri. Atunci cnd un programator este format s lucreze conform cerinelor programrii structurate, construirea algoritmilor, construirea secvenelor de blocuri n schema logic se realizeaz din start pentru cele trei tipuri de structuri fundamentale, nefiind necesar conversia. n cazul n care programatorul are la dispoziie software mai vechi n care apare frecvent instruciunea GOTO trebuie s realizeze conversia de programe, adic s dezvolte astfel de construcii nct s fie eliminat instruciunea GOTO din program. Structurile de program ce conin instruciuni GOTO sunt greu de analizat, modificat, restructurat i testat. De aici i nevoia de a transforma aceste structuri de program n unele din care instruciunile GOTO s lipseasc.
99

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Pentru transformarea programelor ce conin instruciuni GOTO n programe structurate, cea mai utilizat tehnic este cea a introducerii unei variabile de control. Se consider urmtoare structur posibil n cadrul unei aplicaii:

C1

Da

S1

C2

Da S2

C3

Da S3

Figura 5.15 Exemplu de structur de program n care se folosesc instruciuni GOTO

Pentru structurarea secvenei de program din figura 5.15 se introduce variabila de control vb de tip boolean, care va fi iniializat cu valoarea true. Schema rezultat este prezentat n figura 5.16:

100

Abordarea structurat

Figura 5.16 Schema structurat folosind variabila de control vb

Nu toate programele nestructurate au corespondent sub form de program structurat. Se observ c exist situaii, cum este cazul structurilor de tip if-then sau repetitive condiionate posterior, n care rescrierea lor folosind doar structuri fundamentale nu i are rostul. Este i motivul pentru care toate limbajele de programare accept construcii de acest fel, existnd chiar cuvinte cheie speciale, de exemplu, do-while. Nu acelai lucru se spune despre secvenele ce folosesc instruciuni GOTO, care trebuiesc eliminate din cod. Pentru programele deja scrise folosind GOTO, transformarea lor manual reprezint un efort semnificativ, motiv pentru care au fost
101

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

dezvoltate o serie de instrumente software cu ajutorul crora aceast transformare este automatizat.

5.4 Limbaje de programare structurate


Limbajele PASCAL, C, C++ i toate care urmeaz acestora sunt proiectate n vederea implementrii fr nici o rezerv a structurilor de control fundamentale. Avnd n vedere c limbajul C++ este utilizat pentru toate exemplificrile, pentru implementarea structurii alternative din figura 5.2 se realizeaz secvena:
if ( C1 ) { S1; } else { S2; }

Pentru structura repetitiv condiionat anterior n limbajul C++ exist construcia:


while ( condiie ) { S; }

Structura repetitiv condiionat posterior este implementat n C++ prin:


do { S; } while ( condiie );

Pentru structura repetitiv cu contor se realizeaz secvena:


initializari; for ( i = vinit; conditie; i += r ) { S; }

Structura liniar se implementeaz printr-o structur de forma:


I1; I2; ...... Iin;

102

Abordarea structurat

Rezult c pentru schema logic dat n figura 5.7 textul surs C++ este dat n figura 5.17.
#include <stdio.h> #define M #define N 10 10

int m, n, i, j, a[M][N]; int main() { printf("\nIntroducetie numarul de linii: "); scanf("%d", &m); printf("\nIntroduceti numarul de coloane: "); scanf("%d", &n); for ( i = 0; i < m; i++ ) { for ( j = 0; j < n; j++ ) { printf("\na[%d][%d] = ", i, j); scanf("%d", &a[i][j]); } } int nrplus int nminus int nrzero = 0; = 0; = 0;

for ( i = 0;i < m; i++ ) { for ( j = 0; j < n; j++ ) { if ( a[i][j] == 0 ) nrzero++; if ( a[i][j] > 0 ) nrplus++; if ( a[i][j] < 0 ) nrminus++; } } printf("\nNumarul de elemente pozitive este %d",nrplus); printf("\nNumarul de elemente negative este%d",nrminus); printf("\nNumarul de elemente nule este %d\n", nrzero); return 1; }

Figura 5.17 Codul surs n C++ pe baza schemei logice din figura 5.7

Aplicnd metricile de complexitate definite n capitolul Ciclul de dezvoltare software, se obine urmtoarele valori pentru complexitatea ciclomatic: CM =35 25 + 2 = 12

103

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

i pentru metricile Halstead:


Metric Lungimea programului Vocabularul programului Volumul Dificultatea Efort = = = = = Valoare 69 14 421,49 15,38 6480,38

Analiznd variaia complexitii fa de abordarea clasic, unde implementarea a fost tot monolitic, se observ o cretere a complexitii pe fondul diminurii numrului de noduri din graf. Aceasta deoarece au fost folosite structuri repetitive ale limbajului i elaborate de programator. Prin urmare, mai multe instruciuni din programarea clasic au fost grupate ntr-una singur. Acest lucru ns nu a diminuat fluxul de execuie care rmne acelai, dovad numrul aproape identic de arce. Metricile Halstead nu difer foarte mult de valorile nregistrate pentru abordarea clasic, lucru normal, avnd n vedere se efectueaz aceleai operaii logice, pe aceiai parametrii. Comparnd cu abordarea standard, lucrurile stau total diferit. Datorit organizrii mult mai riguroase a codului, n librrii de subprograme, complexitatea programului scade foarte mult, el devenind o succesiune de apeluri de funcii din librrie. n situaia n care se iau n considerare i complexitile funciilor se observ o apropiere a valorilor, n condiiile n care nu s-a mers dect pe primul nivel de derivare, n cadrul bibliotecii de subprograme. Dac ns se realizeaz o implementare i n variant structurat, cu ajutorul mai multor subprograme, se constat o cretere a complexitii. Se construiete un subprogram care realizeaz citirea elementelor matricei de la tastatur i un subprogram care numr elementele din matrice pe baza rezultatului returnat de o funcie transmis ca parametru subprogramului de numrare. Aceast funcie presupune trei implementri pentru comparaiile de tip mai mare, egal i mai mic. Rezultatele obinute pentru metricile de complexitate devin n acest caz: CM =15 respectiv:
Metric Lungimea programului Vocabularul programului Volumul Dificultatea Efort = = = = = Valoare 83 40 356,5 20,08 2116,73
104

Abordarea structurat

Trebuie menionat c evaluarea a fost fcut prin cumularea valorilor obinute i la nivelul subprogramelor, la fel ca n cazul programrii standard. Rezult c, n general, introducerea de subprograme crete complexitatea programului. Avantajul principal este legat de reutilizare. n plus, dac subprogramele nu sunt dezvoltate n cadrul aceluiai proiect, ele nu particip la calculul complexitii, i atunci valoarea acesteia este foarte mic. Programarea structurat reprezint o tehnic de programare care ajut la dezvoltarea de software cu un design i un flux de execuie clare i prin care se asigur un grad ridicat de modularitate a produsului. Eliminarea instruciunii GOTO din programe folosind diverse metode, unele prezentate i n cadrul acestui capitol, ajut la eliminarea unor categorii de erori de programare foarte grave i la mbuntirea calitii codului. Trebuie menionat c aceast tehnic de programare este fundamentat tiinific, prin teoremele de structur, spre deosebire de alte tehnici anterioare ei, care nu posed un astfel de fundament.

105

6.1 Abordarea bottom-up


Tehnica bottom-up presupune construirea la nceput a unor elemente primitive, de baz, apoi combinarea lor n elemente mai complexe, dar i adugarea de noi elemente, pn cnd se obine produsul final. n programarea aceasta nseamn construirea iniial a unor funcii primitive, ce implementeaz elemente atomice de funcionalitate, apoi utilizarea lor n construirea de funcii mai complexe. Rezultatul este o structur arborescent care are ca rdcin produsul software final. Se consider o problem P definit prin date de intrare DI, date de ieire DE, i algoritmi de calcul pe baza crora se obin datele de ieire. Pornind de la rezultate, se definesc din aproape n aproape prelucrri i se ajunge n final la problema P n integralitatea ei. Datele iniiale sunt transformate n date finale dup un numr finit de prelucrri care genereaz i date intermediare. Pornind de la datele de ieire DEij, care pot fi cele finale sau unele intermediare, se asociaz o prelucrare sau un set de prelucrri cu un modul Mij al produsului software, care permite obinerea lor pe baza unor date de intrare intermediare, DIij figura 6.1.

Figura 6.1 Fluxul corespunztor unui modul

106

Programarea modular

n notaia din figura 6.1, indicele inferior arat numrul modulului, iar indicele superior arat nivelul pe care se afl modulul n structura arborescent asociat produsului software. Datele de ieire ale unui modul de pe nivelul j, reprezint datele de intrare pentru unul sau mai multe module de pe nivelul j-1. Proiectantul sistemului software abordeaz ntreaga problematic de la elementele concrete spre elementul de sintez, care se afl la nivelul superior. Se construiete soluia sub form de structur arborescent pornind de la ultimul nivel de descompunere frunzele arborelui, ctre rdcin. Asamblarea se efectueaz de la nivelul j+1 spre nivelul j, continundu-se de la nivelul j spre nivelul j1 pn la nivelul 0 ce corespunde rdcinii. O astfel de abordare permite construcia produsului pornind de la funciile primitive, specifice domeniului problemei, spre funciile complexe ce implementeaz logica aplicaiei; tehnica este potrivit pentru situaii n care specificaiile nu sunt clare, i de asemenea, asigur o mai bun organizare a codului surs. Modulele de pe nivelurile inferioare sunt asamblate n unul sau mai multe module de pe nivelurile superioare. De exemplu, un set de funcii pentru accesul la fiiere este folosit att ntr-un modul de salvare a datelor manipulate de aplicaia software, ct i ntr-un modul de prelucrare care necesit lucrul cu fiiere temporare.
P=M10

M11

M21

M3 1

..

M1p-1

M2p-1

...

Mmp

M 1p

M2p

M3p

...

Mnp

Figura 6.2 Asamblare bottom-up n sensul de la frunze spre rdcin


107

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

De exemplu, pentru problema de calcul matriceal aleas pentru ilustrarea particularitilor tehnicilor de programare, soluia prin tehnologia bottom-up presupune: cunoaterea exact a rezultatelor obinute: numrul componentelor negative, numrul componentelor pozitive i numrul componentelor nule; cunoaterea exact a condiiilor pe care matricea trebuie s le ndeplineasc: matricea este simetric. Printr-o abordare bottom-up, programatorul identific, n primul rnd, funciile primitive: citirea informaiilor de la tastatur, afiarea informaiilor pe ecran, compararea a dou numere pentru care rezultatul are valoarea adevrat sau fals. Aceste funcii se vor gsi pe nivelul de baz a structurii. Pornind de la aceste primitive, se construiesc pe nivelul urmtor, modulul de citire a dimensiunilor i elementelor matricei, modulul de afiare a rezultatelor i a unor mesaje de informare sau de eroare dintr-o list asociat. Pe nivelul al treilea de la baz, apar modulele de stabilire a simetriei matricei, de determinare a minimului i a maximului, precum i de numrare a elementelor pozitive, negative i nule din matrice. Aceste module se bazeaz pe funciile de comparare a dou numere, de afiare de rezultate i afiare de mesaje. Pe nivelul rdcin, se apeleaz aceste module conform fluxului cerut de problem. nseamn c structura arborescent are 4 niveluri, (figura 6.3).

Figura 6.3 Dezvoltarea bottom-up pentru problema PROB


108

Programarea modular

Se impun urmtoarele observaii referitoare la figura 6.3: un modul de pe un nivel inferior, cum este cazul modului de Afiare mesaje din lista de mesaje s fie implicat n construirea mai multor module de pe nivelurile superioare; un modul de pe un nivel inferior, cum este cazul modulului Compararea a dou numere particip la construcia unui alt modul care nu se afl neaprat pe urmtorul nivel n ierarhie. Rezult c, structura nu este arborescent n proporie de 100%, ea permind ca un nod copil s aib mai mult de un nod printe. ns caracterul ierarhic se menine, prin faptul c modulele sunt dezvoltate ncepnd cu cele primitive, de baz, i terminnd cu cele complexe, respectiv cu produsul final ca ultim modul, iar acestea din urm au n construcia lor apeluri ctre modulele de baz. Se construiete tabelul 6.1 care evideniaz faptul c datele de intrare ale unui modul de pe nivelul k sunt ieiri ale modulului de pe nivelul k 1. Corelaia nivel mod de utilizare variabile Tabelul 6.1
Nivel Modul c1 c2 c3 c4 c5 c6 c7

3 3 3 2 2 2 1 1 1 0

citire informaii afiare informaii comparare numere citire matrice afiare rezultate afiare mesaje contorizare maxim/minim simetrie main()

E I E I/E I E I/E I E I/E E I/E I I

I E I I I I/E

E I I I I/E

E I/E

Semnificaia coloanelor c1 c7 este prezentat mai jos. c1 c2 c3 c4 c5 c6 c7 nrplus nrnegativ nrnull text matricea

dimensiuni matrice
max/min
109

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Avantajul acestei abordri este dat de faptul c programatorul rezolv pri ale problemei, ofer rezultate intermediare i pe msur ce poate asambla module, obine n final produsul finit. Dezvoltarea bottom-up corespunde proceselor industriale care realizeaz repere, prin asamblare se obin subansambluri, iar la cel mai nalt nivel se obine produsul finit.

6.2 Abordarea top-down


Abordarea top-down presupune divizarea problemei mari n subprobleme mai mici care sunt tratate separat pn la nivelul unor rutine sau module primitive. Proiectarea unui program modular, prin aceast tehnic se face astfel: modulul de nivel superior specific ce niveluri descendente ale sale sunt necesare i precizeaz ce date se transmit i ce rezultate se ateapt de la ele. Modulele terminale se vor identifica i implementa, deci, ultimele. Testarea programului se face n aceeai abordare: mai precis, proiectarea, programarea i testarea modulului descendent se vor realiza mpreun. Dac modulul printe a fost pus la punct atunci, pe parcursul implementrii modulului descendent, eventualele erori vor aprea numai n acesta din urm. Programatorul se va putea, deci, concentra numai pe realizarea acestui modul, munca lui devenind mult mai eficient. Problema P a afirii numrului de elemente pozitive, negative, nule, a maximului i minimului unei matrice simetrice, este privit, ca orice aplicaie informatic, ca avnd o structur arborescent pe dou niveluri, figura 6.4.

Figura 6.4 Structura arborescent top-down pe dou niveluri

SP1 reprezint subproblema corespunztoare iniializrii datelor; SP2 reprezint subproblema de prelucrare a datelor; SP3 reprezint subproblema de afiare a rezultatelor.
110

Programarea modular

Dezvoltarea top-down presupune efectuarea unor detalieri pentru fiecare subproblem, dup cum urmeaz: S-SP11 corespunde iniializrii dimensiunilor matricei, care este subproblem a lui SP1; S-SP12 corespunde iniializrii matricei, care este subproblem a lui SP1; S-SP13 corespunde alegerii minimului dintre numrul de linii i numrul de coloane ale matricei pentru a stabili dimensiunea matricei pentru care se analizeaz simetria.

6.5.

Structura arborescent asociat subproblemei SP1 este dat n figura

Figura 6.5 Descompunerea pe subprobleme a funciei de iniializare

Pentru efectuarea prelucrrilor, subproblema SP2 este descompus n subprobleme dup cum urmeaz: S-SP21 corespunde testrii caracterului simetric dup diagonala principal; S-SP22 corespunde testrii caracterului simetric dup diagonala secundar; S-SP23 corespunde testrii simetriei dup coloana din mijloc; S-SP24 corespunde testrii simetriei dup linia din mijloc; S-SP25 corespunde aflrii elementului minim din matricea simetric; S-SP26 corespunde aflrii elementului maxim din matricea simetric S-SP27 corespunde contorizrii.

111

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Structura arborescent este dat n figura 6.6.

Figura 6.6 Descompunerea pe subprobleme a funciei de calcul

Afiarea rezultatelor impune descompunerea subproblemei SP3 astfel: S-SP31 corespunde afirii elementului minim; S-SP32 corespunde afirii elementului maxim; S-SP33 corespunde afirii numrului de elemente nule, pozitive, respectiv negative; S-SP34 corespunde afirii de mesaje.

Descompunerea acestei funcii este dat n figura 6.7.


SP3

S-SP31

S-SP32

S-SP33

S-SP34

Figura 6.7 Descompunerea pe subprobleme a funciei de afiare

Aceast descompunere corespunde situaiei n care problema este foarte bine neleas, experiena analitilor i designerilor permit asocierea unei structuri arborescente clare, iar duplicarea de cod este controlat. Pentru aceast abordare se procedeaz astfel: se scrie programul apelator SP0, definind variabilele de baz i apelurile la procedurile corespunztoare lui SP1, SP2, SP3; n faza de analiz sunt clarificate numrul de niveluri, inputurile corespunztoare fiecrui nivel;
112

Programarea modular

se scriu procedurile SP1, SP2, SP3, n fiecare dintre ele, incluzndu-se apelurile de proceduri de tipul S-SPij, i = 1,2,3 j = 1,2, ...., ni; se scriu procedurile corespunztoare frunzelor structurii arborescente.

Produsul se dezvolt de la ntreg spre parte, ceea ce confer designerului resurse suficiente pentru a obine un produs complet, prin adugri de proceduri la fiecare nivel, dac este cazul.

6.3 Raportul subprograme modul


Conceptul de modul este foarte cuprinztor, fiind asociat unei prelucrri cu un grad de complexitate acceptabil, care s-i ofere un nivel de autonomie ridicat. De exemplu, exist modulul de validare date, modul de sortare date, modul de calcul matriceal, modul de actualizare fiier, modul de preluare inputuri, modul de afiare, modul de conversie etc. Fiecare modul este format din unul sau mai multe subprograme. ntr-un caz particular, un modul este format dintr-un singur subprogram. n realitate, un modul are n structura sa mai multe subprograme. De exemplu, modulul de validare a datelor include: validarea cmpului alfabetic; validarea unui cmp dac este numr ntreg; validarea apartenenei numrului ntreg la un interval; validarea apartenenei unui ir la o mulime de subiruri descris explicit; validarea numerelor reale; validarea apartenenei unui numr real la un interval; validarea apartenenei unui numr la o mulime dat prin elemente. Modulul pentru iniializarea unui masiv unidimensional include subprograme pentru: iniializarea de la tastatur; iniializarea dintr-un fiier; iniializarea prin atribuire; iniializarea prin rezultatul evalurii unei expresii.
113

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Complexitatea unui modul este rezultatul analizei contextului i filosofiei adoptate de ctre echipa de proiectani software. Dac se urmrete un nivel de complexitate ridicat pentru module, structura arborescent se organizeaz pe un numr sczut de niveluri. Modulele complexe se afl pe acelai nivel, funcie de raportul cu prinii, respectiv descendenii si. Dac se adopt ipoteza ca modulele s aib un nivel de complexitate redus, structura arborescent are un numr de niveluri ridicat. n acest context, pentru problema de calcul matriceal, n ipoteza un modul = un subprogram, lista subprogramelor este prezentat n continuare: citire_dim() - citete dimensiunile matricei de la tastatur; citire_mat() - citete elementele matricei de la tastatur; simetrie1() stabilete simetria matricei fa de diagonala principal; simetrie2() stabilete simetria matricei fa de diagonala secundar; contorplus() numr elementele pozitive dintr-o matrice; contorminus() numr elementele negative dintr-o matrice; contornul() numr elementele nule ale unei matrice; minim() identific minimul elementelor unei matrice; maxim() identific maximul elementelor unei matrice; afiseaza() afieaz rezultatele prelucrrilor; mesaj() afieaz mesaje specifice ale aplicaiei. Dac se procedeaz la regruparea ntr-un modul a mai multor subprograme, structura pentru aceeai problem este dat n figura 6.9.

Figura 6.9 Structura aplicaiei, dup gruparea mai multor subprograme ntr-un singur modul
114

Programarea modular

Se urmrete realizarea unui echilibru ntre numrul de module i dimensiunea aplicaiei. O aplicaie simpl, dar cu un numr mare de module nu face dect s creasc complexitate. Pe de alt parte, o aplicaie complex nu foarte bine delimitat pe module, afecteaz la rndul ei complexitatea, prin faptul c influeneaz alte caracteristici de calitate cum sunt mentenabilitatea sau reutilizabilitatea. Modulele din figura 6.9, sunt transpuse n codul surs, n limbajul C++, sub forma unor perechi de fiiere cu extensiile .h respectiv .cpp. Astfel, exist citire.h i citire.cpp, validare.h i validare.cpp, prelucrare.h i prelucrare.cpp, respectiv afisare.h i afiare.cpp. Codul surs pentru operaiile de citire este dat n figura 6.10 (citire.cpp).
void citire_dimensiuni(int *m, int *n) { printf("Introduceti numarul de linii ale matricei = "); scanf("%d", m); printf("\nIntroduceti numarul de coloane ale matricei = "); scanf("%d", n); } void citire_mat(int a[][N], int m, int n) { for (int i = 0; i < m; i++ ) { for (int j = 0; j < n; j++) { printf("a[%d][%d] = ", i, j); scanf("%d", &a[i][j]); } } }

Figura 6.10 Codul surs al modulului de citire

Modulul de validare are codul surs din figura 6.11 (validare.cpp).


int simetrie1( int a[][N], int m, int n) { int result = 1; for (int i = 0; result && i < m; i++ ) { for (int j = 0; result && j < n; j++ ) { if ( a[i][j] != a[j][i] ) { result = 0; } } } return result; } int simetrie2( int a[][N], int m, int n) { int result = 1; for (int i = 0; result && i < m; i++ ) {
115

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

for (int j = 0; result && j < n; j++ ) { if ( a[i][j] != a[m-i-1][n-j-1] ) { result = 0; } } } return result; }

Figura 6.11 Codul surs al modulului de testare a simetriei

Pentru modulul de prelucrri, implementare n C++ este dat n figura 6.12 (prelucrare.cpp).
int contor(int a[][N], int m, int n, int prag, int(*func)(int, int)) { int contor = 0; for ( int i = 0; i < m; i++ ) { for ( int j = 0; j < n; j++ ) { if ( func(a[i][j],prag) > 0) { contor++; } } } return contor; }

int minim (int a[][N], int m, int n) { int min = a[0][0]; for ( int i = 0; i < m; i++ ) { for ( int j = 0; j < n; j++ ) { if ( min > a[i][j] ) min = a[i][j]; } } return min; } int maxim (int a[][N], int m, int n) { int max = a[0][0]; for ( int i = 0; i < m; i++ ) { for ( int j = 0; j < n; j++ ) { if ( max < a[i][j] ) max = a[i][j]; } } return max; }

Figura 6.12 Codul surs pentru modulul de prelucrri


116

Programarea modular

n final, codul surs pentru modulul de afiare mesaje i rezultate este dat n figura 6.13 (afisare.cpp)
void afiseaza(char* mesaj, int result) { printf("%s %d\n", mesaj, result); } void mesaj(int cod) { switch(cod) { case 1: printf("Matricea este simetrica!\n"); break; case 2: printf("Matricea nu est simetrica!\n"); break; } }

Figura 6.13 Codul surs pentru modulul de afiare

n aceste condiii, programul care determin numrul de elemente pozitive, negative i nule din cadrul unei matrice citit de la tastatur, i care este scris folosind modulele descrise anterior, are urmtorul cod surs:
int maimare(int a, int b) { return a > b; } int maimic(int a, int b) { return a < b; } int egal( int a, int b) { return a == b; } int main() { int a[M][N], m, n; citire_dimensiuni(&m, &n); citire_mat(a, m, n); //numara elementele pozitive, negative si nule afiseaza("Numarul de elemente pozitive este", contor(a, m, n, 0, maimare)); afiseaza("Numarul de elemente negative este", contor(a, m, n, 0, maimic)); afiseaza("Numarul de elemente nule este", contor(a, m, n, 0, egal)); return 1; }
117

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Cele trei funcii maimare, maimic, egal sunt transmise ca parametrii funciei de contorizare, n aa fel nct aceasta din urm capt un grad ridicat de generalitate, putnd numra orice tip de element din matrice care trebuie s respecte o condiie, condiie stabilit prin funcia transmis ca parametru. Programarea modular se bazeaz tot pe filozofia programrii structurate. Aceasta din urm permite divizarea programelor n module ce sunt implementate i testate pe calculator n mod independent. Abordarea modular, fie ca este bottom-up sau top-down, nu aduce un plus de complexitate, ci doar reorganizeaz acelai cod surs rezultat din programarea structurat. Prin urmare, pentru exemplul considerat, valorile complexitii obinute la abordarea structurat, pentru cazul folosirii de funcii n implementarea soluiei problemei i nu n abordarea tip monolit, rmn valabile i pentru programarea modular. Exist o component a complexitii care se modific, i anume, cea cognitiv, pentru c, prin descompunerea programului n module, cu funcionaliti clare, bine delimitate, crete inteligibilitatea codului i prin urmare el devine mai uor de neles de ctre programator, chiar dac, n esen este acelai cod. Aceast component ns nu se reflect n nici o msur cantitativ a complexitii.

6.4 Parametrizarea
La dezvoltarea programelor trebuie s se ia n considerare modificri ce vor apare n timp, la nivelul: datelor de intrare, n sensul introducerii de cmpuri, modificrii de domeniu, creterii dimensiunii i volumului de date, schimbrii criteriilor de cutare; formulelor de calcul, prin adugarea, eliminarea i nlocuirea de operatori i de operanzi, prin adugarea i eliminarea de formule; rezultatelor, prin adugarea de noi rezultate care trebuie obinute, prin schimbarea coninutului unor rezultate existente i prin eliminarea unora dintre acestea.

Dac structura produsului software este gndit rigid, orice modificare la nivel conceptual se reflect prin succesiuni de modificri n textul surs, modificri caracterizate prin efecte de antrenare multipl, imprevizibile. De
118

Programarea modular

aceea, trebuie ca programele s fie concepute astfel nct s preia toate modificrile prin introducerea unor parametri de ctre utilizatorul produsului software. De exemplu, n matricea pentru care se efectueaz prelucrri, trebuie terse unele linii, respectiv, unele coloane. Dac programul este construit rigid, trebuie definite dou proceduri, una de tergere linie din matrice i alta de tergere coloan, iar programatorul trebuie s le activeze n program, dup ce s-a fcut citirea matricei iniiale din fiier. O alt variant const n definirea nc de la nceputul elaborrii produsului software a doi vectori, unul pentru gestionarea liniilor, iar cellalt pentru gestionarea coloanelor, care vor avea valorile 1, dac linia, respective coloana este activ i 0 n caz contrar. Dac programul este conceput rigid, iar la un moment dat se impune ca operaiile pe matrice s nu ia n considerare una din simetrii, trebuie ca subprogramele de testare a simetriei s fie scoase, necesitnd operaii n cascad asupra produsului. Proiectarea flexibil va impune un parametru pe care l iniializeaz utilizatorul cu 1 dac se lucreaz pe matrice simetric i 0 dac se lucreaz pe toat matricea. n cazul unor evaluri de expresii, se introduc coeficieni, care prin iniializare cu -1 sau cu 1, vor determina evaluri de expresii diferite, iar ali coeficieni iniializai cu 1 sau 0 vor extinde sau vor restrnge formulele. De exemplu, pentru evaluarea expresiilor: E1 = a + b + c + d + h + g + p E2 = a + b - c + d - h + g - p E3 = a - b - c - d E4 = a + b + d + h + p E5 = a - b + c - d + h + g p se procedeaz astfel: variabilele a, b, c, d, h, g, p sunt memorate n componentele x[0], x[1], x[2], x[3], x[4], x[5], respectiv, x[6]; se construiete vectorul k[7], care se iniializeaz cu +1, dac termenii se adun sau cu -1, dac termenii se scad; se construiete vectorul s[7] care se iniializeaz cu 1 dac variabila particip la evaluarea expresiei, respectiv cu 0, n caz contrar;

119

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

se construiete vectorul e[5], n care se evalueaz una din cele 6 expresii.

Utilizatorul produsului software nu are altceva de fcut dect s iniializeze vectorii k[] i s[]. Tabelul 6.2 conine valorile celor doi vectori pentru cele cinci expresii. Iniializrile variabilelor de structur ale expresiei Tabelul 6.2
a b c d h g p a b c d h g P k[0] k[1] k[2] k[3] k[4] k[5] k[6] s[0] s[1] s[2] s[3] s[4] s[5] s[6] E1 +1 E2 +1 E3 +1 E4 +1 E5 +1 +1 +1 -1 +1 -1 +1 -1 -1 +1 +1 +1 +1 -1 +1 -1 +1 -1 +1 +1 +1 +1 +1 +1 +1 +1 +1 -1 +1 +1 -1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 0 +1 +1 +1 +1 +1 +1 +1 +1 0 +1 +1 +1 +1 0 0 +1 +1 +1 0 +1 +1

n cazul n care apar probleme de stabilire a apartenenei la intervale i prin program se definesc n instruciuni if limitele intervalelor, ori de cte ori se modific limitele, se modific numrul de intervale, trebuie operat n program. De exemplu, pentru evaluarea expresiei a, dac x < -1 2 a , dac x [1, 1] e= 3 a , dac x (1, 7] a 4 , n rest secvena de program este
if ( x < -1 ) { e = a; } else if ( x <= 1 ) { e = a * a; } else if ( x <= 7 ) { e = a * a * a; } else { e = a * a * a * a; } ............
120

Programarea modular

Se accept ideea introducerii de la tastatur a numrului K de intervale, iniializarea a doi vectori cu limitele inferioare i limitele superioare ale K intervale. Se stabilete o modalitate de preluare a expresiilor ce trebuie calculate. Ori de cte ori se modific numrul de intervale K i limitele intervalelor, utilizatorul modific parametrii. Nu se intervine asupra textului surs. Programarea modular presupune existena unor subprograme cu caracteristici de calitate excelente, destinate execuiei unor operaii de baz. Subprogramele acestea se ncorporeaz n module, permind creterea gradului de complexitate a prelucrrilor, meninndu-se nivelul ridicat al performanei.

121

7.1 Proiectarea orientat obiect


Paradigma orientrii pe obiecte are marele avantaj al unor instrumente mai bune de reprezentare a problemei, prin combinarea caracteristicilor i a comportamentului unei entiti ntr-o singur construcie. De exemplu, pentru problema definit n capitolul Ciclul de dezvoltare software, dezvoltarea aplicaiei software n manier structurat, presupune: definirea unor variabile n cadrul programului, pentru a memora informaiile cu privire dimensiunile matricei i la elementele componente ale acesteia; definirea de funcii crora li se transmit aceste informaii i care realizeaz prelucrrile specifice. Dezavantajul acestei abordri rezid n faptul c datele sunt gestionate n cadrul aplicaiei separat de funcionalitate. Aceasta nseamn c o seciune de cod n aplicaie este legat strns prin control i transfer de informaii, de multe alte seciuni ale aplicaiei. Aceste dependene apar cnd sunt folosite variabile globale, de exemplu. n abordarea orientat obiect, separarea nu mai exist. Informaiile sunt memorate n interiorul obiectului, fiind astfel protejate la accesul din exterior, iar funciile au acces direct la ele, fr a mai fi nevoie s fie transmise ca parametrii. Datorit acestor avantaje au fost dezvoltate metodologii de analiz i proiectare orientate obiect a aplicaiilor software. Proiectarea orientat obiect are n vedere identificarea i separarea responsabilitilor. Posibilitatea reutilizrii codului rezid tocmai n faptul c acel cod nu are elemente specifice pentru un anumit domeniu sau aplicaie; el trebuie s delege toat responsabilitatea legat de aspecte specifice ale domeniului ctre seciuni specifice ale aplicaiei. Designul orientat obiect este unul responsability-driven. De aceea, procesul de design ncepe cu analiza comportamentului, pentru c, spre deosebire de structurile de date i specificaiile formale ale apelurilor de funcii, care ajung s fie cunoscute i stabilite mult mai trziu, n urma analizei mult mai
122

Programarea orientat obiect

profunde a problemei, comportamentul, adic ceea ce ateapt utilizatorul s fac aplicaia pentru el, este descris nc de la nceput, n termeni cu semnificaie att pentru programatori ct i pentru client. Prima aciune a echipei de proiectare software este de a rafina i clarifica specificaiile iniiale ale clientului, care, de cele mai multe ori sunt neclare i incomplete. De asemenea, trebuie avut n vedere posibilele modificri de specificaii ce apar ulterior i care afecteaz produsul n procesul de dezvoltare. De aceea, structura produsului software trebuie gndit n aa fel nct impactul modificrilor de specificaii s fie minim. Ingineria software este simplificat prin identificarea i dezvoltarea de componente software. O component este o entitate abstract care realizeaz anumite aciuni, adic ndeplinete anumite responsabiliti. n fazele iniiale ale procesului de dezvoltare nu este important s se cunoasc reprezentarea exact a unei componente sau cum realizeaz o anumit aciune. n final, o component se concretizeaz ntr-o funcie, structur sau clas, sau o colecie de alte componente. Sunt importante dou caracteristici: o component trebuie s aib un set redus bine definit de responsabiliti; interaciunea dintre componente trebuie s fie minim. Identificarea componentelor se realizeaz n momentul n care se imagineaz procesul de execuie a sistemului; asta nseamn stabilirea aciunilor efectuate i identificarea entitilor care le efectueaz. Orict de bine este condus procesul de specificare a cerinelor i de proiectare a produsului software, ntotdeauna este nevoie s se intervin ulterior n formularea cerinelor i n structura produsului, datorit unor noi cerine ale utilizatorului sau rafinrii unora deja existente. Programatorii i designerii software trebuie s anticipeze aceste situaii i s minimizeze impactul lor. Printre aciunile pe care trebuie s le ntreprind pentru aceasta, se numr: obiectivul principal este minimizarea numrului de componente afectate de o schimbare de cerine. Chiar i n cazul schimbrilor majore, acesta nu trebuie s afecteze prea multe seciuni de cod; identificarea nc de la nceput a codului surs cel mai predispus n viitor la schimbri i izolarea efectelor acestor schimbri; cele mai frecvente modificri in de interfee, de formatele de comunicare, de formatele rezultatelor;
123

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

reducerea cuplrii dintre componente, ceea ce reduce dependena dintre ele i crete posibilitatea modificrii uneia cu implicaii minime asupra celeilalte.

Pe lng comportament, componentele conin i informaii. O component reprezint o pereche constituit din comportament i stare. comportamentul unei componente este setul de aciuni pe care le realizeaz; descrierea complet a comportamentului unei componente se mai numete i protocol. starea unei componente reprezint toate informaiile memorate n interiorul ei. Nu este necesar ca toate componentele s menin informaii de stare, ns majoritatea componentelor vor fi o combinaie de comportament i stare. Dou concepte importante folosite n proiectarea componentelor software sunt cuplarea i coeziunea. Coeziunea reprezint msura n care responsabilitile unei singure componente formeaz un tot semnificativ. O coeziune ridicat este obinut prin asocierea aciunilor care sunt relaionate dintr-un anumit punct de vedere, ntr-o singur component. Cuplarea descrie relaia dintre componentele software. n general, este de dorit minimizarea dependenelor dintre componente, din moment ce acestea afecteaz reutilizarea codului, uurina n modificare i dezvoltare. n particular, cuplarea este crescut atunci cnd o component software trebuie s acceseze informaiile de stare ale altei componente. Aceste situaii trebuie evitate, o modalitate este ca aciunea respectiv s fie transferat ca responsabilitate componentei care memoreaz informaia de stare dorit. Atunci cnd o component dezvoltat de un programator este utilizat de un altul, este obligatoriu ca acesta din urm s tie cum s o foloseasc i mai puin s tie cum a fost implementat. Folosirea unei componente presupune cunoaterea responsabilitilor pe care le are, adic a aciunilor disponibile i nu cum aceste aciuni sunt implementate. Aceasta reprezint separarea dintre interfa i implementare. Separarea este necesar din mai multe motive: ascunderea detaliilor de implementare ine de o caracteristic fundamental a programrii orientate obiect, i anume ncapsularea, deoarece nu este relevant i nici nu ar trebui s intereseze pe un programator care folosete o component cum sunt implementate funcionalitile sale;
124

Programarea orientat obiect

implementarea comportamentului unei componente se schimb; atta timp ct interfaa expus pentru celelalte componente nu se schimb, impactul modificrii implementrii este minim. De exemplu, exist o component folosit pentru salvarea unor informaii pe disc; o implementare iniial este salvarea ntr-un fiier binar; ulterior ns, se dorete salvarea ntr-o baz de date sau un fiier xml. Modificarea modului n care se salveaz datele nu trebuie s afecteze implementarea celorlalte componente care utilizeaz aceast funcionalitate.

Implementarea componentelor software se face prin intermediul construciilor de tip clas, puse la dispoziie de limbajele de programare. Nu toate limbajele de programare sunt 100% orientate obiect. De exemplu, limbajul C++ permite n continuare construcii din limbajul C, care nu sunt orientate obiect: funcii definite n afara claselor, variabile globale etc.

7.2 Clasele
Programarea orientat obiect aduce n plus fa de celelalte construcii ale altor tehnici de programare, un conglomerat numit clas. n [MSPCD97], clasa este definit ca o categorie generalizat ce descrie un grup de elemente particulare, numite obiecte, care fac parte din ea. O clas reprezint un instrument de descriere utilizat n programare pentru a defini o entitate sub cele dou aspecte: al caracteristicilor sale, definite prin atributele clasei i al comportamentului su, definit prin metodele clasei. Prin comportamentul unei entiti se nelege modul n care aceasta reacioneaz la interaciunea cu alte entiti. Definirea unei clase se realizeaz prin: precizarea operanzilor sau a atributelor; funciile membre; proprietile asociate componentelor pentru a stabili modaliti de referire. O clas este un tip de dat definit de utilizator printr-o construcie de forma:
class nume { element 1; element 2; . element n; }

125

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Un element este fie variabil de tip fundamental sau de tip derivat, n cazul atributelor, fie respectiv o funcie. Rezult c o clas se descrie sub forma:
class nume { tip1 variabila1; tip2 variabila2; . tipn variabilan; tip1 functie1 ( lista parametrii 1 ); tip2 functie2 ( lista parametrii 2 ); . tipm functiem ( lista parametrii m ); }

Clasele difer de structurile de tip articol prin faptul c elementelor din componen li se asociaz restricii de referire cu ajutorul specificatorilor de control. Aa cum variabilele n programe sunt de tip global i local sau dup modul de alocare sunt statice i dinamice, tot astfel, pentru a defini o anumit disciplin n manipularea claselor se asociaz grupurilor de elemente din clas un specificator de control al crui cmp de aciune este anulat de un altul. Specificatorii de control sunt: public ceea ce nseamn c elementul respectiv este accesibil oricrei clase externe; private nseamn c numai elementele componente ale aceleai clase au dreptul de a accesa acest membru; protected prin care disponibilitatea elementului include disponibilitatea specificatorului private, i, n plus, asigur disponibilitatea elementului pentru elementele ce urmeaz a fi definite n clasele derivate din clasa curent.

Funciile membru ale clasei refer oricare dintre variabilele definite n clas. La proiectarea unei clase se au n vedere urmtoarele aspecte: funciile membru s acopere ntreaga gam de prelucrri; s fie definite ct mai multe forme de iniializare a operanzilor; ntre variabilele i funciile membre s fie o concordan perfect pentru a nu apare erori n execuia programelor ce folosesc clase.
126

Programarea orientat obiect

Programarea orientat obiect este tehnica de programare fundamentat pe conceptul de reutilizare software. Pentru a atinge acest obiectiv trebuie ca: procedurile s efectueze prelucrri complete i corecte; referirea procedurilor s se efectueze rapid i uor, fr a fi nevoie de informaii inutile din moment ce funciile membre utilizeaz variabile definite n aceeai clas; manipularea claselor s conduc la obinerea de noi clase, iar gradul de generalitate s fie ct mai ridicat. De exemplu, dac se dorete implementarea calculului cu numere complexe, se definete clasa Complex care trebuie s aib o structur de tip articol pentru a grupa partea real i partea imaginar a numrului complex i s conin funcii membre pentru operaiile de adunare, scdere, nmulire, mprire, ridicare la putere i extragere de radical. Aceast clas se definete n secvena de surs:
class Complex { private: struct compl { float real; float img; } c; public: void aduna ( Complex& cpl ) { c.real = c.real + cpl.c.real; c.img = c.img + cpl.c.img; } void scade ( Complex& cpl ) { c.real = c.real - cpl.c.real; c.img = c.img - cpl.c.img; } void produs ( Complex& cpl ) { c.real = c.real * cpl.c.real - c.img * cpl.c.img; c.img = c.real * cpl.c.real + c.img * cpl.c.img; } void divide ( Complex& cpl ) { float temp; temp = cpl.c.real * cpl.c.real - cpl.c.img * cpl.c.img;

127

Analiza comparat a complexitii entitilor text generate prin tehnici de programare c.real = ( c.real * cpl.c.real - c.img * cpl.c.img ) / temp; c.img = ( c.real.*cpl.c.img - c.img * cpl.c.real ) / temp; } .. }

Aa cum sunt definite funciile membru ale clasei Complex, au asociat specificatorul de control public. Clasele sunt bine construite dac la elaborarea unui program principal apar numai referiri de funcii membre din clase.

7.3 Constructori i destructori


Constructorii sunt metode cu acelai nume ca al clasei, utilizai pentru construirea instanelor clasei. Ei se execut de cte ori se aloc memorie pentru o nou instan a clasei, dup ce s-a produs alocarea de memorie. Este recomandat ca o clas s conin mai multe declarri de constructori, care vor diferi ntre ele prin numrul i tipul parametrilor transmii. n felul acesta, se asigur un grad mai mare de utilizabilitate al clasei, dat fiind posibilitile diferite de instaniere. Limbajul C++ pune la dispoziia utilizatorilor trei tipuri de alocri de memorie: static, atunci cnd o variabil este declarat n afara oricrei funcii sau cnd pentru un atribut se folosete modificatorul static. Un atribut static este comun tuturor instanelor derivate clasei din care provine; automatic, care se face pentru variabile definite n cadrul corpului unei funcii; memoria alocat este dealocat atunci cnd se prsete corpul funciei; dinamic, care se face pe heap, la cererea explicit a programatorului.

Destructorii sunt metode ale clasei referii nainte de a se produce dealocarea zonei de memorie asociate elementelor clasei. O clas nu are dect un singur destructor. Destructorul este o procedur care se definete prin numele clasei, fr a avea list de parametrii, fiind precedat de operatorul ~; pentru clasa Complex destructorul are forma ~Complex().
128

Programarea orientat obiect

Att constructorii, ct i destructorii nu au tipuri asociate. Forma constructorilor variaz de la o clas la alta, n funcie de specificul fiecreia, dar i de experiena i obiectivele proiectantului clasei. Exist o form de constructor, numit constructor de copiere, foarte util n special atunci cnd se transmit obiecte ca parametrii prin valoare. Constructorul de copiere primete ca unic parametru o referin la un alt obiect al aceleai clase. Implementarea cea mai frecvent presupune copierea efectiv a valorilor atributelor obiectului transmis ca parametru n atributele obiectului nou. De exemplu, pentru clasa Complex se identific urmtorii constructori pentru iniializarea: cu variabile corespunztoare membrilor structurii care stocheaz atributele numrului complex; cu un alt obiect din aceeai clas.
Complex ( float a, float b ) { c.real = a; c.img = b; } Complex ( Complex& cpl ) { c.real = cpl.c.real; c.img = cpl.c.img; }

Corespunztor, textele surs de definire a constructorilor sunt:

7.4 Proprietile claselor


Programarea orientat obiect dezvolt noi abordri prin faptul c obiectele i clasele se bucur de o serie de proprieti.

7.4.1

ncapsularea

Este rezultatul regruprii operanzilor i funciilor membre ntr-un conglomerat numit clas. Operanzii i operatorii clasei interacioneaz, formnd un tot unitar. De exemplu, se consider clasa Matrice. ncapsularea revine la a defini operanzii care se refer la numrul de linii, numrul de coloane i elementele matricei n clas, precum i funciile care efectueaz operaiile de calcul, formnd un tot unitar. Funciile folosesc direct operanzii ntruct
129

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

prin ncapsulare este dreptul lor de a referi ceva definit pe un domeniu comun. n limbajul FORTRAN instruciunea COMMON avea menirea de a implementa germeni ai ncapsulrii asociind zone de memorie grupate unor operanzi, fr a mai fi nevoie de a-i nscrie n lista de parametrii exact ca n cazul ncapsulrii propriu-zise. Pentru efectuarea operaiilor de numrare elemente pozitive, negative i nule, precum i pentru testarea simetriei matricei lista parametrilor este nul, deoarece toate informaiile necesare sunt deja definite n cadrul clasei i folosite ca atare, nemaifiind nevoie s fie transmise ca parametrii, codul surs al clasei Matrice este:
class Matrice { protected: int nrCol; int nrLinii; int mat[M][N]; public: Matrice( int m, int n ) { nrCol = m; nrLinii = n; for ( int i = 0; i < m; i++ ) { for ( int j = 0; j < n; j++ ) { mat[i][j] = 0; } } } Matrice( int a[][N], int m, int n ) { nrCol = m; nrLinii = n; for ( int i = 0; i < nrLinii; i++ ) { for ( int j = 0; j < nrCol; j++ ) { mat[i][j] = a[i][j]; } } } Matrice( Matrice& m ) { nrCol = m.nrCol; nrLinii = m.nrLinii; for ( int i = 0; i < nrLinii; i++ ) { for ( int j = 0; j < nrCol; j++ ) { mat[i][j] = m.mat[i][j]; } } } bool simetrie1() { bool result = true; if ( nrCol != nrLinii ) {

130

Programarea orientat obiect


result = false; } else { for ( int i = 0; result && i < nrLinii; i++ ) { for ( int j = 0; result && j < nrCol; j++ ) { result = mat[i][j] == mat[j][i]; } } } return result; } int contorplus() { int contor = 0; for ( int i = 0; i < nrLinii; i++ ) { for ( int j = 0; j < nrCol; j++ ) { if ( mat[i][j] > 0 ) { contor++; } } } return contor;

} int contorminus() { int contor = 0; for ( int i = 0; i < nrLinii; i++ ) { for ( int j = 0; j < nrCol; j++ ) { if ( mat[i][j] < 0 ) { contor++; } } } return contor; } int contornul() { int contor = 0; for ( int i = 0; i < nrLinii; i++ ) { for ( int j = 0; j < nrCol; j++ ) { if ( mat[i][j] == 0 ) { contor++; } } } return contor; }

131

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

7.4.2 Motenirea
Este o proprietate deosebit de important, pe baza ei sunt construite clasele din aproape n aproape, organizndu-se pe niveluri de agregare. Clasele agregate de pe nivelul k preiau operanzii i funciile membre ale claselor de pe nivelul k-1, care intr prin derivare n componena lor, precum i proprietile acestora. De exemplu, dac se dorete mbogirea clasei Matrice cu funcii pentru determinarea minimului i maximului elementelor din cadrul matricei, se construiete o nou clas Matrice2, unde, pe lng funciile deja existente ale clasei se adaug noile metode pentru aflarea minimului, respectiv, maximului, clasa obinut avnd codul surs:
class Matrice2 : public Matrice { public: int minim () { int min = mat[0][0]; for ( int i = 0; i < nrLinii; i++ ) { for ( int j = 0; j < nrCol; j++ ) { if ( min > mat[i][j] ) { min = mat[i][j]; } } } return min; } int maxim () { int max = mat[0][0]; for ( int i = 0; i < nrLinii; i++ ) { for ( int j = 0; j < nrCol; j++ ) { if ( max < mat[i][j] ) { max = mat[i][j]; } } } return max; } };

Avantajele folosirii motenirii sunt: reutilizabilitatea cnd o funcionalitate este motenit din alt clas, codul respectiv nu trebuie rescris, el trebuie doar apelat n noul context; o alt implicaie este legat de fiabilitatea codului,
132

Programarea orientat obiect

deoarece prin motenire, o anumit funcionalitate este scris doar la nivelul unei clase i apoi motenit i utilizat n toate clasele derivate; consistena interfeei cnd dou sau mai multe clase sunt derivate din aceeai clas printe, se asigur faptul c comportamentul motenit este acelai pentru toate clasele; componentele software motenirea d posibilitatea programatorilor s construiasc componente software reutilizabile i gruparea lor n biblioteci; n acest fel, efortul de dezvoltare al unui produs nou este diminuat prin utilizarea de librrii cu funcionalitate deja implementat; dezvoltarea rapid de prototipuri atunci cnd sistemul software este construit folosindu-se componente reutilizabile, timpul de dezvoltare este concentrat pe nelegerea elementelor specifice ale sistemului; astfel se construiesc versiuni de sistem, numite prototipuri, care pun accent pe aspectele critice ale sistemului. Un prototip este dezvoltat, utilizatorii l folosesc, iar a doua versiune a sistemului este realizat pe baza experienei acumulat cu prima i a feedbackului de la utilizatori.

Dei motenirea prezint foarte multe avantaje, exist i o serie de costuri de care trebuie s se in seama n momentul proiectrii ierarhiilor de clase: viteza de execuie este influenat prin prisma faptului c metodele motenite, care au un caracter mai general, sunt de regul mai lente dect codul specializat; ns afectarea vitezei de execuie este compensat cu creterea vitezei de dezvoltare; dimensiunea programelor este influenat n sensul c devine mai mare n cazul programelor care folosesc librrii de componente, dect programele care folosesc cod specializat, deoarece nu toate componentele dintr-o librrie sunt folosite n proiect, dar librria trebuie adugat n totalitatea sa; complexitatea programelor o ierarhie de clase introduce un anumit grad de complexitate n sistem; cu ct ierarhia este mai mare, nivelurile de abstractizare mai multe, cu att sistemul care folosete aceast ierarhie este mai complex.

133

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

7.4.3 Polimorfism
n limbajele de programare, un obiect polimorfic este orice entitate, cum ar fi o variabil sau argument de funcie, creia i este permis s stocheze valori de tipuri diferite pe durata execuiei programului. Funciile polimorfice sunt acelea care au argumente polimorfice. n programarea orientat-obiect, polimorfismul reflect principiul substituibilitii, i anume, o variabil polimorfic poate stoca o valoare a tipului su declarat sau a oricrui subtip al tipului declarat. Polimorfismul funciilor reprezint posibilitatea de a asocia acelai nume la diferite funcii. Evitarea ambiguitii n procesul de referire se obine prin: atribuirea de liste de parametrii de lungimi diferite; atribuirea de liste de parametrii cu aceeai lungime, dar parametrii corespunztori ca poziie au tipuri diferite; funciilor, polimorfismul poart i numele de

n cazul suprancrcare.

Pentru clasa Matrice se definete operaia de adunare a dou matrice. Implementarea operaiei se face prin dou metode, denumite aduna, difereniate prin lista de parametrii. Clasa Matrice devine:
class Matrice { . void aduna (Matrice& m ) { aduna(m.mat, m.nrLinii, m.nrCol ); } void aduna ( int a[][N], int m, int n ) { for ( int i = 0; i < m; i++ ) { for ( int j = 0; j <n ; j++ ) { mat[i][j] += a[i][j]; } } } };

Cele dou metode sunt polimorfice; au acelai nume, iar stabilirea apelului corect se face la execuie, n funcie de numrul, tipul i poziia parametrilor. O alt situaie n care se pune problema polimorfismului o reprezint suprascrierea metodelor. Prin motenire, clasa derivat preia metodele expuse de clasa printe, conform cu regulile de derivare. ns, ea are posibilitatea s furnizeze o alt implementare pentru o metoda motenit.
134

Programarea orientat obiect

Practic, se definete o metod n clasa derivat cu aceeai semntur cu cea din clasa printe, dar care are o alt implementare. n momentul execuiei, metoda din clasa derivat este identificat i executat naintea metodei din clasa printe. Suprascrierea se folosete atunci cnd, pentru o anumit funcionalitate, exist o implementare implicit la nivelul clasei printe, implementare care poate fi rafinat prin suprascriere, n clasele derivate, dac se dorete acest lucru. De exemplu, pentru metoda simetrie1() din clasa Matrice se furnizeaz o alt implementare n clasa derivat Matrice2, prin care simetria este testat att pentru diagonala principal, ct i pentru diagonala secundar. Textul surs este:
class Matrice { public: virtual bool simetrie1() { . } }; class Matrice2 : public Matrice { public: bool simetrie1() { //test pentru diagonala principala bool result = Matrice::simetrie1(); //test pentru diagonala secundata if ( nrCol == nrLinii ) { for ( int i = 0; result && i < nrLinii; i++ ) { for ( int j = 0; result && j < nrCol; j++ ) { if ( mat[i][j] != mat[nrColi-1][nrCol-j-1] ) { result = false; } } } } else { result = false; } return result; } };

135

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Se observ c n implementarea din clasa Matrice2 se folosete rezultatul implementrii din clasa Matrice, n plus testndu-se i simetria fa de diagonala secundar. Apelarea implementrii din clasa printe nu este o cerin obligatorie atunci cnd se suprascrie o metod, dar este o practic recomandat, deoarece, teoretic, suprascrierea trebuie s aduc ceva n plus fa de o prelucrare general, ntr-un context particular, al clasei derivate.

Suprancrcarea operatorilor
Reprezint un mod elegant de a pune n coresponden simbolurile unor operatori cu proceduri complexe de prelucrare, specifice unor tipuri de date derivate. Limbajul Basic a avut implementat adunarea, scderea, nmulirea de numere i adunarea de matrice. Prin suprancrcarea de operatori se creeaz premisele evalurii de calcule matriceal scriind expresiile direct, cu operatori de calcul i operanzi matrice. n acest fel, operatorul + este pus n coresponden cu procedura de adunare matrice, operatorul este pus n coresponden cu procedura scdere matrice, operatorul * este pus n coresponden cu nmulirea de matrice, iar operatorul = este pus n coresponden cu copierea de matrice. Urmtorii operatori nu se suprancarc: ([]) operatorul de selectare a unei componente membre ntr-o structur de tip articol; (*) operatorul de deferire a unei componente din clas; (::) operatorul de selecie a funciei membru dintr-o clas; operatorul de tratare variabile globale; (?:) operatorul condiional.

Pentru suprancrcarea operatorului binar numit operator, se utilizeaz definirea:


tip1 operator simbol_operator ( tip2, tip3 )

unde: tip1 tipul rezultatului returnat; tip2 tipului primului operand; tip3 tipul celui de-al doilea operand.
136

Programarea orientat obiect

Dac suprancrcarea operatorului simbol_operator este realizat n clasa numit classa, definirea operatorului n afara clasei se realizeaz prin:
tip1 classa::calcul simbol_operator (tip2, tip3)

n exemplul de mai jos se prezint suprancrcarea operatorului + pentru a nsemna adunarea a dou matrice i a operatorului pentru a nsemna scderea a dou matrice pornind de la clasa Matrice.
class Matrice { void aduna (Matrice& m ) { aduna(m.mat, m.nrLinii, m.nrCol ); } Matrice& operator + (Matrice& m ) { aduna(m); return *this; } Matrice& operator - (Matrice& m ) { for (int i = 0; i < nrLinii; i++ ) { for ( int j = 0; j < nrCol; j++ ) { mat[i][j] = mat[i][j] m.mat[i][j]; } } return *this; } };

Datorit concepiei total diferite cu privire la modul n care o aplicaie este proiectat i implementat, evaluarea complexitii necesit utilizarea unor metrici specifice. Rezultatele furnizate de metricile prezentate n capitolul Ciclul de dezvoltare software, i anume, complexitatea ciclomatic i metricile Halstead nu sunt relevante. Pentru aplicaia care rezolv problema considerat ca exemplu de control n aceast carte, se construiete clasa Matrice, iar programul apelator instaniaz aceast clas cu date citite de la tastatur i va apela diverse metode ale clasei pentru a obine rezultatele cerute. Valorile metricilor enunate anterior suport, n acest caz dou niveluri de agregare; ele sunt determinate la nivelul metodelor clasei, sunt agregate la nivelul clasei, i n final, la nivelul ntregii aplicaii. Rezultatele sunt:
Metric Complexitatea ciclomatic (v) Lungimea programului Vocabularul programului Dificultatea = = = = Valoare 29 238 92 35,33
137

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Analiznd comparativ cu rezultatele obinute prin celelalte tehnici de programare, exist clar o cretere de complexitate, care are diverse cauze: existena unor construcii specifice programrii orientateobiect, cum sunt constructorii, metodele de acces la atributele clasei etc.; analiza ntregii clase, nu numai a unora dintre funciile implicate n fluxul aplicaiei, din motivul c, o clas este privit ca un tot unitar, i prin urmare trebuie neleas de ctre programator n totalitatea sa; dei informaiile referitoare la dimensiunile i elementele matricei sunt nglobate n clas, i prin urmare, nu sunt transmise ca parametrii, acest lucru nu este surprins de metricile Halstead de complexitate, care iau n considerare, n fiecare dintre metodele clasei, atributele acesteia ca fiind operanzi distinci, lucru ce contribuie la creterea nejustificat a valorilor acestor metrici. De aceea, pentru analiza complexitii programelor orientate obiect, sunt utilizate metrici specifice. Exist dou tipuri de metrici: unele se refer la interdependena dintre clase i se numesc metrici de cuplare, altele se refer la consistena clasei i se numesc metrici de coeziune. Aceste metrici sunt n legtur cu caracteristicile specifice ale programrii orientate obiect: ncapsulare, motenire, polimorfism, interaciunea dintre obiecte. Metricile de coeziune sunt legate n principal de dimensiunea claselor. Unele cele mai relevante metrici din aceast clas de metrici sunt: numrul de atribute ale clasei (NOA), mprit n numrul de atribute ale instanei de clas (NOI) i numrul de atribute statice (NOS); numrul de metode ale clasei (NOM), mprit n numrul de metode publice (NOP), i numrul de metode private (NOPV); aceste metrici sunt mrimi ale ncapsulrii; gradul de ncapsulare (GI), vzut ca raport ntre numrul de elemente private ale clasei i numrul total de elemente. Aceast mrime trebuie s fie ct mai aproape de valoarea 1. Pentru atribute, el trebuie s fie ntotdeauna 1.

138

Programarea orientat obiect

Pentru exemplul considerat, n care exist clasele Matrice i Matrice2, se obin urmtoarele valori pentru metricile prezentate mai sus:
Metric NOA NOI NOS NOM NOP NOPV GI = = = = = = = Matrice 3 3 0 7 7 0 0,33

Se observ lipsa metodelor de tip privat, ceea ce nseamn c funcionalitatea expus este foarte mare, practic toate metodele clasei sunt prezente n interfaa acesteia. O clas cu o interfa bogat n metode are un nivel de complexitate mai mare dect al unei clase care expune mai puine metode n interfaa sa, deoarece prima necesit un efort de nelegere din partea programatorului mai mare, cel puin teoretic, dect a doua. Metricile de cuplare sunt legate, n principal, de interaciunea dintre obiecte sau dintre clase. Interaciunea dintre obiecte se identific n parametrii transmii n apelurile de metode, instanierea de obiecte locale de tipuri diferite, tipul rezultatului apelului unei metode. Dou clase sunt cuplate atunci cnd metodele declarate n una dintre ele folosesc metode declarate n cealalt. O cuplare excesiv afecteaz nu numai reutilizabilitatea claselor, dar i complexitatea acestora datorit numrului mare de legturi dintre clase care determin o nelegerea mai greoaie a codului de ctre programator. Avantajele programrii orientate obiect sunt nenumrate, printre cele mai importante regsindu-se i reutilizarea codului. Prin intermediul mecanismelor de derivare, se obine acces la funcionalitatea de baz a obiectului, cu posibilitatea modificrii acesteia prin mecanisme polimorfice, cum sunt suprascrierea metodelor sau suprancrcarea operatorilor. Prin derivare, se obin clase noi, ce modeleaz mai atent anumite aspecte ale entitilor reale sau abstracte utilizate n modelul aplicaiei software.

139

8.1 Premise
Programarea orientat obiect ofer o abordare unitar asupra fenomenelor modelate de aplicaiile software att din punct de vedere al datelor, ct i al prelucrrilor. Acest lucru a fcut ca aceast tehnic de programare s se impun n detrimentul celorlalte. Programarea orientat obiect a dus i la construirea de metodologii de dezvoltare software orientate obiect. Un aspect foarte important n activitatea de programare l constituie reutilizarea codului. Acest lucru se face prin construirea de librrii cu elemente de cod, cum sunt funciile sau clasele de obiecte, i utilizarea acestora n noi aplicaii. Principiile de construire a unor astfel de librrii au fost expuse n capitolele Programarea standard i Programarea orientat obiect. Datorit dezvoltrii i rspndirii de noi limbaje i tehnologii de programare, a aprut o prim mare problem: cum se poate folosi o funcionalitate scris ntr-un limbaj de programare i nglobat ntr-o bibliotec, n cadrul unei aplicaii scrise n alt limbaj de programare? Aceasta este problema interoperabilitii dintre limbajele i tehnologiile diferite de programare. Situaia aceasta este foarte frecvent ntlnit, deoarece o companie care utilizeaz software pentru desfurarea activitilor sale, achiziioneaz acest software pe principii de eficien i cost, mai puin pe principii legate de tehnologii i limbaje folosite. Inevitabil, la un moment dat, acest software va trebui s comunice, pentru rezolvarea unor probleme mai complexe. Pentru aceasta, au fost fundamentate componentele. Programarea bazat pe componente reprezint o extensie a programrii orientate obiect n care elementul central este componenta. Componenta este definit ca program sau obiect binar de dimensiuni mici, cu funcionalitate specific, bine definit, proiectat ntr-o manier care

140

Utilizarea de componente

permite combinarea cu alte componente i/sau aplicaii. Modelul unei aplicaii care utilizeaz componente este prezentat n figura 8.1:
I1 COMP1

PRODUS SOFTWARE

I2

COMP2 .

In

COMPn

Figura 8.1 Modelul unei aplicaii care folosete componente

Componentele se mpart n trei mari categorii, dup cum urmeaz: componente care ofer servicii utilizatorilor de aplicaii; aici intr n principal componentele vizuale, care sunt afiate pe ecranele cu care lucreaz utilizatorii aplicaiei; componente care ofer servicii de business i care implementeaz reguli de business, cum sunt de exemplu, reguli de calcul al impozitelor i taxelor, modaliti de livrare etc.; rezultatele lor sunt furnizate componentelor din prima categorie, pentru afiarea ctre utilizator; componente care ofer acces la date; acestea sunt componente prin care se permite conectarea la baze de date, la alte aplicaii mai vechi, i care furnizeaz date serviciilor din categoria anterioar, de business, pentru prelucrri.

8.2 Software orientat pe componente


Ingineria software bazat pe componente folosete principii legate de modularitate, abstractizare, ncapsulare. Primul pas este crearea specificaiilor pentru interfa. Interfaa unei componente reprezint setul de metode de prelucrare pe care componenta le expune spre utilizare celorlalte

141

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

componente i/sau aplicaii. Principiul este simplu i are precedent n abordarea orientat obiect: atta timp ct funcionalitatea oferit nu se schimb, modul n care aceasta este implementat nu conteaz pentru utilizatorul componentei. Interfaa trebuie s aib o serie de caracteristici: s fie consistent, adic funcionalitile oferite s se refere la o aceeai entitate real; de exemplu, o interfa care expune funcionaliti legate de lucrul cu matrice, nu poate conine funcionaliti legate de lucrul cu fiiere; s fie clar, ceea ce nseamn c metodele din interfa s exprime clar funcionalitatea oferit; s fie scurt, deoarece o interfa cu foarte multe metode este greu de neles i de folosit de ctre programatori.

Rezultatul acestei faze este un document de specificaii privind interfaa componentei i, eventual, o descriere a acesteia ntr-un limbaj specializat. O component poate expune mai multe interfee, gndite ca subseturi de funcionalitate pe care componenta o implementeaz. Motivul este urmtorul: diveri utilizatori ai componentei au nevoie doar de anumite metode ale acesteia, prin urmare, expunerea ntregii interfee ctre ei, n primul rnd ngreuneaz utilizarea componentei, dar i deschide posibiliti de afectare a strii componentei de ctre utilizatori care nu ar trebui s o afecteze. Prin urmare, expunerea de interfee diferite pentru tipuri diferite de utilizatori nseamn i implementarea unui mecanism de securitate la nivelul componentei. Pentru problema definit n capitolul Ciclul de dezvoltare software, se imagineaz urmtoarea interfa ce este expus unei alte aplicaii, interfa descris folosind notaia UML:

Figura 8.2 Exemplu de interfa pentru componente

Se observ c interfaa are o metod de iniializare a componentei cu date referitoare la matrice, o metod pentru determinarea minimului i una

142

Utilizarea de componente

pentru determinarea maximului dintre elementele matricei, iar ultima metod numr elementele din matrice, astfel: dac flag = 1, elementele mai mari dect valoarea specificat n parametrul k; dac flag = 2, elementele mai mici dect valoarea specificat n parametrul k; dac flag = 3, elementele egale cu valoarea specificat n parametrul k;

Cuvntul in care precede fiecare parametru indic faptul c respectivul este parametru de intrare. O alt interfa a componentei conine operaiile de adunare, scdere i nmulire. Descrierea, folosind notaia UML este dat n figura 8.3:
interface MatriceINTF2 +initializare(in nrLinii : long(idl), in nrCol : long(idl), in elemente : any(idl)) +aduna(in matrice : any(idl)) +scade(in matrice : any(idl)) +inmulteste(in matrice : any(idl)) +numarLinii() : long(idl) +numarColoane() : long(idl)

Figura 8.3 Interfaa componentei Matrice pentru operaii cu masive

Se observ c, pe lng metodele corespunztoare operaiilor cu masive, exist i dou metode, cu rol de accesorii pentru cmpuri de date ale componentei. Fiecare dintre operaiile de baz, adunare, scdere, nmulire primete ca parametru o alt component de acelai tip cu aceasta, iar rezultatul este memorat n componenta curent. Pentru c o component este scris ntr-un limbaj de programare i folosit n alt limbaj de programare, mecanismul de construire a instanelor de componente este diferit fa de programarea orientat obiect. Din acest motiv este necesar o metod separat de iniializare a datelor componentei. Pasul al doilea nseamn crearea specificaiilor pentru componente, ce includ interfeele i funciile membre. Pornind de la specificaiile interfeelor, se elaboreaz modelul obiectual al componentei care include, pe lng clasa principal, i un set de clase ajuttoare. Obiectivul este de a asigura dezvoltatorilor o specificaie complet att din punct de vedere al funcionalitii implementate, ct i din punct de vedere al modului n care aceasta va fi implementat. Prin urmare, n aceast etap se ine cont de tehnologia ce este folosit la dezvoltarea componentei.

143

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

Odat ce specificaiile pentru component au fost ntocmite, programatorii ncep dezvoltarea propriu-zis. Unitatea de testare n ingineria software bazat pe componente este realizat prin crearea unei alte componente, care testeaz interfeele i funciile membre ale acesteia. Fiecare programator va trebui s i construiasc o a doua component prin care s testeze funcionalitatea componentei iniiale. Motivaia acestei abordri este urmtoarea: n primul rnd, fiecare funcionalitate, nainte de a fi folosit trebuie supus unei faze de testare; programatorul are obligaia ca funcionalitatea implementat, pe care el o ofer, s fie deja testat; tehnica se numete unit-testing i vizeaz stabilirea urmtoarelor: conformitatea funcionalitii cu specificaiile: componenta face ceea ce este specificat s fac; implementarea reacioneaz corespunztor i n situaiile excepionale de prelucrare: cazuri extreme, fluxuri alternative de prelucrare etc. n al doilea rnd, se testeaz comunicarea ntre component i mediul extern; practic, se simuleaz modul n care componenta va fi folosit n cadrul unor aplicaii concrete.

Faza de testare individual (unit-testing) a componentei presupune la rndul alte dou faze: testarea componentei ca i clas (pentru c la baz nu este altceva dect o clas); aceasta presupune testarea direct a metodelor componentei att cele private, ct mai ales cele publice; testarea componentei prin interfeele expuse; aceast testare trebuie s aduc n plus, fa de rezultatele celei anterioare, informaii despre cum sunt primii i tratai parametrii de intrare, cum se scriu datele n parametrii de ieire.

Dezvoltarea unei componente difer n funcie de tipul de component i tehnologia folosit. Fiecare tehnologie are propriile mecanisme. ntr-un fel sunt scrise componentele folosind tehnologia COM i limbajul C++ i n alt mod sunt scrise componentele folosind tehnologia EJB mpreun cu limbajul Java. Pentru exemplificare, s-a folosit tehnologia COM folosind

144

Utilizarea de componente

ATL i limbajul C++. Astfel, interfaa din figura 8.2 se scrie n felul urmtor, folosind IDL + Interface Definition Language:
[ object, uuid(F8AE2674-8836-433E-B809-D6DB90BFA8E9), dual, helpstring("IMatrice Interface"), pointer_default(unique) ] interface IMatrice : IDispatch { [id(1), helpstring("method initializare")] HRESULT initializare(int nrLinii, int nrCol, int* mat); [id(2), helpstring("method minim")] HRESULT minim(int* min); [id(3), helpstring("method maxim")] HRESULT maxim(int* max); [id(4), helpstring("method contor")] HRESULT contor(int flag,int k, int* numar); }; [ uuid(E64BA31E-7FBC-47CE-A993-474502FD2CB2), version(1.0), helpstring("Matrix 1.0 Type Library") ]

Pentru scrierea interfeei au fost utilizate mecanismele de tip wizard din cadrul mediului de dezvoltare Microsoft Visual Studio 6.0. Clasa C++ care implementeaz interfaa are urmtorul cod surs:
class ATL_NO_VTABLE CMatrice : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CMatrice, &CLSID_Matrice>, public IDispatchImpl<IMatrice, &IID_IMatrice, &LIBID_MATRIXLib> { public: CMatrice() { } DECLARE_REGISTRY_RESOURCEID(IDR_MATRICE) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CMatrice) COM_INTERFACE_ENTRY(IMatrice) COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() // IMatrice

145

Analiza comparat a complexitii entitilor text generate prin tehnici de programare public: STDMETHOD(contor)(int flag,int k, int* numar); STDMETHOD(maxim)(int* max); STDMETHOD(minim)(int* min); STDMETHOD(initializare)(int nrLinii, int nrCol, int* mat); private: int n; int m; int a[M][N]; }; . STDMETHODIMP CMatrice::initializare(int nrLinii, int nrCol, int* mat) { m = nrLinii; n = nrCol; for ( int i = 0; i < m; i++ ) { for ( int j = 0; j < n; j++ ) { a[i][j] = mat[i*m + j]; } } return S_OK; } STDMETHODIMP CMatrice::minim(int *min) { *min = a[0][0]; for ( int i = 0; i < m; i++ ) { for ( int j = 0; j < n; j++ ) { if ( a[i][j] < *min ) { *min = a[i][j]; } } } return S_OK; } STDMETHODIMP CMatrice::maxim(int *max) { *max = a[0][0]; for ( int i = 0; i < m; i++ ) { for ( int j = 0; j < n; j++ ) { if ( a[i][j] < *max ) { *max = a[i][j]; } } } return S_OK; }

146

Utilizarea de componente
STDMETHODIMP CMatrice::contor(int flag, int k, int *numar) { int i = 0; int j = 0; *numar = 0; switch ( flag ) { case 1: for ( ; i < m; i++ ) { for ( ; j < n; j++ ) { if ( a[i][j] > k ) ( *numar )++; } } break; case 2: for ( ; i < m; i++ ) { for ( ; j < n; j++ ) { if ( a[i][j] < k ) ( *numar )++; } } break; case 3: for ( ; i < m; i++ ) { for ( ; j < n; j++ ) { if ( a[i][j] == k ) ( *numar )++; } } break; } return S_OK; }

Se observ c, pe lng clasa C++ propriu-zis, care implementeaz funcionalitatea componentei, mai sunt implicate o serie de alte clase, specifice tehnologiei de a cror scriere se ocup wizard-ul, mbuntindu-se astfel productivitatea. De asemenea, tipurile de date i mai ales modul n care sunt transmii parametrii i rezultatele difer fa de situaiile normale din programarea orientat obiect. De exemplu, rezultatul prelucrrii se returneaz printr-un parametru de tip ieire declarat n lista de parametrii; funcia returneaz un cod de succes sau de eroare specific. De asemenea, nu orice tip de dat este permis; numai tipurile fundamentale, irurile de caractere i pointerii apar n listele de parametrii ale metodelor componentei expuse prin interfa. Pentru metodele din interiorul componentei, nevizibile n afar, se folosesc i alte tipuri de date. Pentru evaluarea complexitii componentelor, metricile din capitolul Ciclul de dezvoltare software nu sunt relevante pentru c filozofia componentelor se refer la utilizarea acestora sub form binar, n care nu

147

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

are importan caracteristicile codului surs ci capacitatea componentei de a oferi funcionalitatea ateptat. Tot din acelai motiv, al lipsei accesului la codul surs, nici metricile specifice abordrii orientate obiect, unele enunate n capitolul Programarea orientat obiect nu sunt aplicabile. De asemenea, deoarece, componentele se bazeaz pe diferite tehnologii, dezvoltarea lor presupune nu numai doar scrierea funcionalitii dar i a codului surs ajuttor, specific fiecrei tehnologii n parte. Prin mecanismele de tip wizard, mare parte din codul surs ajuttor este generat deja, programatorul trebuind doar s adauge metodele specifice ce implementeaz funcionalitatea componentei. Datorit caracterului binar al componentelor, trebuie luate n considerare metrici care au legtur cu utilizarea componentei n aplicaii i practic surprind complexitatea componentei din punct de vedere al utilizrii ei i nu din punct de vedere al construciei; astfel de metrici sunt: numrul de metode dintr-o interfa (NMI), numrul de parametrii ai metodelor dintr-o interfa (NPM), mprit n numrul parametrilor de intrare (NPI), numrul parametrilor de ieire (NPE) i numrul parametrilor de intrare/ieire (NPIE); acestea sunt mrimi ale complexitii interfeei componentelor; numrul de interfee expuse de component (NI), numrul de metode de iniializare a acesteia (NIM); acestea sunt mrimi ale disponibilitii componentei. Pentru exemplul considerat, valorile metricilor enumerate anterior sunt:
Metric NMI NPM NPI NPE NPIE = = = = = Interfaa1 4 9 5 4 0 Interfata2 6 8 6 2 0

Referitor la metricile din categoria a doua, componenta construit expune dou interfee i are o singur metod de iniializare. Se observ c o metod poate face parte din mai multe interfee; de aceea, o agregare a metricilor anterioare la nivelul componentei nu are relevan, datorit riscului multiplicrii valorilor pentru metodele prezente n mai multe interfee.

148

Utilizarea de componente

8.3 Biblioteci de componente


Pentru a fi distribuite i utilizate, componentele sunt grupate n biblioteci de componente. Bibliotecile de componente sunt asemeni bibliotecilor de funcii sau de clase. Dei, n ambele cazuri, reutilizarea codului se face sub form binar, prin specificul construciei lor, bibliotecile de componente, permit utilizarea unor funcionaliti scrise ntr-un limbaj de programare sau folosind o anumit tehnologie, n cadrul unor aplicaii scrise folosind alte limbaje de programare sau tehnologii. n acest scop au fost dezvoltate mecanisme specifice prin care se realizeaz integrarea de componente n aplicaii. O bibliotec de componente trebuie s ndeplineasc o serie de criterii, ca s poate fi utilizabil n mod corespunztor n aplicaii: s fie general: componentele din cadrul librriei s ofere funcionaliti comune, generale; s fie consistent: toate componentele din cadrul bibliotecii s se refere la un anumit subiect sau domeniu; de exemplu, o bibliotec de componente pentru lucrul cu structuri de date conine o component pentru lucrul cu masive, o component pentru lucrul cu liste simple i dublu nlnuite, o component pentru lucrul cu arbori; s fie documentat: bibliotecile sunt structuri binare reutilizabile. Dezvoltatorul nu are acces la codul surs pentru a stabili care este interfaa componentei pe care dorete s o foloseasc i nici nu poate tii exact ce anume este implementat pentru o anumit funcionalitate; de aceea orice bibliotec trebuie nsoit de o documentaie detaliat, care s ofere toate aceste informaii astfel nct utilizarea ei s fie foarte facil.

Proiectarea i dezvoltarea bibliotecilor de componente se face ntr-o manier asemntoare cu proiectarea i dezvoltarea bibliotecilor de funcii i clase pentru un limbaj de programare. Construirea bibliotecilor de componente se realizeaz n mai multe moduri: arbitrar, atunci cnd componente potenial reutilizabile sunt grupate n librrii, iar reutilizarea lor depinde foarte mult de cunotinele despre ele ale programatorilor;

149

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

bazat pe cerere, prin care dezvoltatorii de produse software sunt ncurajai s solicite pieei componente pentru diferite funcionaliti; de exemplu, se solicit o component pentru lucru cu masive bidimensionale. Dac exist suficient de multe cereri pentru o anumit component, atunci acea component este dezvoltat, la cerere i nglobat ntr-o librrie; bazat pe dezvoltarea de ctre companie a unui set de componente, proprietare, pe care dezvoltatorii s le foloseasc n cadrul aplicaiilor. Aceast abordare este de regul la ndemna firmelor puternice, care i pot permite s investeasc timp i bani n dezvoltarea de librrii de componente. Pe de alt parte, pentru produse specifice i foarte pretenioase, este necesar chiar ca firma s aib propriile componente pentru funcionalitile critice, chiar dac acestea ar putea fi achiziionate din alt parte, tocmai pentru a avea un control mai bun asupra produsului.

8.4 Asigurarea interoperabilitii de componente

prin

utilizarea

Obiectivul principal al dezvoltrii de componente este de a permite reutilizarea unei anumite funcionaliti implementat ntr-un limbaj de programare, n cadrul unei aplicaii dezvoltat n alt limbaj de programare. Decizia de a implementa i folosi componente trebuie s se bazeze pe urmtoarele argumente: costul dezvoltrii unei componente, raportat la numrul previzibil de utilizri ale acelei componente; dac o component este dezvoltat spre a fi folosit doar n cadrul unei aplicaii, atunci efortul necesar acestui proces este prea mare, pentru c tehnologiile folosite pentru construirea de componente, n general sunt complexe, nu sunt facil de manevrat i pentru aceasta sunt necesari oameni bine pregtii. Dac utilizarea ulterioar este foarte sczut, se opteaz pentru o implementare clasic, orientat obiect a funcionalitii, cu riscul duplicrii implementrii pentru fiecare din utilizrile ulterioare. exist situaia n care o anumit funcionalitate este optim implementat folosind un anumit limbaj de programare; de

150

Utilizarea de componente

exemplu, lucrul cu fiiere sau cu periferice este mult mai rapid pentru programele dezvoltate n C/C++ dect Java sau C#. De aceea, se opteaz pentru dezvoltarea de componente n C++ care s lucreze cu periferice, la un nivel mai apropiat de hardware, urmnd ca restul funcionalitii s fie dezvoltat ntr-un limbaj ca Java sau C#, din care se vor face apeluri ctre metodele componentei respective. Bineneles, aceast abordare este viabil doar n situaia n care ctigul de performan conteaz foarte mult n economia execuiei aplicaiei; dac nu este att de important acest ctig de performan, din nou, soluia clasic, orientat obiect este mult mai puin costisitoare. Interoperabilitatea aplicaiilor reprezint capacitatea acestora de a comunica, de a partaja funcionalitate i informaii, chiar dac aplicaiile ruleaz n medii diferite, au fost concepute i realizate folosind limbaje de programare sau tehnologii diferite. Soluiile de interoperabilitate sunt numeroase, dar de cele mai multe ori sunt specifice unui anumit grup de aplicaii. Soluiile de tip componente au la baz un standard de implementare i utilizare, care asigur o uniformitate n abordarea interoperabilitii. Componentele sunt dezvoltate pe baza unor schelete bine stabilite, interfeele sunt descrise prin instrumente standardizate, utilizarea componentelor n aplicaii se face ntr-o manier clar i bine definit. Standardizarea mecanismelor de comunicare dintre componente are mai multe avantaje: din punct de vedere al dezvoltatorului, este suficient s cunoasc un singur mecanism pentru a nelege diversele implementri i utilizri ale acestuia; din punct de vedere al productorului de software, permite un mai bun management al aplicaiilor pe care le produce i le distribuie i, implicit, costuri mult mai mici; din punct de vedere al calitii aplicaiilor, pentru c, dei poate o soluie particular, specific unui anumit context, este mai performant, costul pierderii de performan este mult mai mic dect costul mentenanei ulterioare a unei soluii specifice, proprietare.

n ultima vreme, a aprut un nou tip de arhitectur de aplicaii, care vizeaz reutilizare maxim de funcionalitate i permite interoperabilitate

151

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

facil, i anume arhitecturile orientate pe servicii. Serviciul este, de fapt, tot o component, ns, cu mecanismul de comunicare complet standardizat i bazat pe un schelet mult mai uor de folosit. Problema major a componentelor tradiionale, de tip COM/DCOM, din punct de vedere al dezvoltrii, o reprezenta complexitatea foarte mare a tehnologiei, lucru care era descurajant de multe ori pentru productorii de software, pui n situaia de a decide utilizarea lor. Prin intermediul serviciilor, acest impediment este eliminat; dezvoltarea este mult mai uoar, comunicarea cu un astfel de serviciu de asemenea. Pentru servicii, se folosete SOAP ca protocol de invocare a metodelor, folosit peste protocolul HTTP. SOAP se bazeaz pe XML pentru structurarea informaiei transferate. n acest fel, nu mai sunt implicate mecanisme de comunicare specifice unui anumit sistem de operare, cum era cazul componentelor tradiionale. Din punct de vedere al unui dezvoltator, serviciile WEB sunt o extensie a tehnologiei distribuite. Practic, aplicaiile sunt rezultatul combinrii prelucrrilor interne i prelucrrilor asigurate se serviciile WEB disponibile. Apare conceptul de software ca serviciu (software as service). Asemeni componentelor, serviciile WEB sunt ncapsulate complet; dezvoltatorul care le folosete nu trebuie s cunoasc detalii de implementare; funcionalitatea expus de serviciu este descris n interfaa sa, prin intermediului unui limbaj specific, WSDL Web Services Definition Language. Conceptul de software ca serviciu contribuie foarte mult la depirea granielor de integrare, inclusiv n cadrul organizaiei. Muli dezvoltatori i arhiteci de sistem vd serviciile WEB ca o opiune excelent pentru integrarea aplicaiilor i mult mai uor de implementat dect soluiile clasice bazate pe componente COM/DCOM de exemplu, sau cele orientate pe mesaje (comunicarea dintre aplicaii se face prin intermediul unui strat intermediar de mesaje). Acest lucru devine foarte important cnd se pune problema integrrii n extranet i permite interoperabilitatea dintre diversele locaii ale companiei sau dintre parteneri, clieni i furnizori. Dac se expune funcionalitate prin servicii WEB, bazate pe SOAP/XML i descrise ntr-un fiier WSDL, oricine o poate accesa fr s fie nevoie de aplicaii specifice care s se potriveasc platformei de tehnologie folosit pentru dezvoltarea funcionalitii.

152

Prezentarea tehnicilor de programare are menirea de a evidenia evoluia n timp a unui domeniu deosebit de important pentru tehnologia informaiei. Trecerea de la o tehnic de programare la alta este rezultatul natural al acumulrii de experien i rezultatul evoluiei structurilor hardware marcat de creterea vitezei de calcul, creterea capacitii de memorare i creterea numrului i tipurilor de echipamente periferice. Toate acumulrile evideniaz tendina spre performan, spre creterea productivitii muncii i creterea calitii produselor software. Indiferent de tehnica de programare ntrebuinat n dezvoltarea de aplicaii informatice, un rol deosebit revine persoanelor analiti i programatori, care definesc probleme, proiecteaz soluii i dezvolt cod surs. n mod natural, dezvoltarea de aplicaii informatice trebuie s urmeze cerinele tehnologiei pe obiecte sau cele ale tehnologiei pe componente. n cazul n care apare necesitatea reutilizrii de software, integrarea de componente elaborate folosind tehnici de programare mai vechi, devine eficient dac i numai dac aceste tehnici sunt cunoscute i se opereaz pe textele surs existente. Cunoaterea tehnicilor de programare permite identificarea unor pri stabile care se regsesc n toate structurile de programe i stabilirea acelor pri care difer radical de la o tehnic la alta. Separarea acestora permite ndreptarea eforturilor spre a executa trecerea a ct mai multor componente dintr-o categorie n alta n vederea obinerii unui echilibru ct mai stabil. Exist situaii cnd sisteme informatice din generaii mai vechi, aflate n exploatare curent, trebuie reproiectate pentru a prelua facilitile oferite de noile tehnologii. Existena de programe translatoare care automatizeaz procesul impune definirea unor parametri. Corectitudinea procesului de translatare depinde de nivelul de cunoatere a inputurilor, adic de nivelul de cunoatere a tehnicii sub care a fost dezvoltat sistemul informatic mai vechi. Este important s se cunoasc tehnicile de programare existente pentru a crea premisele evoluiei spre alte noi tehnici, atunci cnd se identific noi

153

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

cerine, noi exigene i se stabilesc limitele prin care se caracterizeaz att tehnicile de programare vechi, ct i cele de programare noi. Analiza complexitii software realizat pentru implementrile soluiei problemei PROB folosind diferite tehnici de programare, a artat ca exist o influen a abordrilor pe care fiecare tehnic o promoveaz asupra complexitii softwareului rezultat. ns, de asemenea, trebuie remarcat faptul c, pentru anumite tehnici de programare cum este cea orientat obiect sau cea bazat pe componente, metricile clasice, cum sunt cele prezentate n aceast carte, respectiv complexitatea ciclomatic i metricile Halstead, nu au relevan. n tabelul 9.1 sunt sintetizate rezultatele obinute pe codurile surs ale implementrilor pentru diferitele tehnici de programare, ale problemei PROB. Complexitile implementrilor problemei PROB Tabelul 9.1
Indicator Tehnica de programare Complexitate ciclomatic Dificultate (Halstead)

Abordarea clasic Programarea standard Programarea structurat Programarea modular Programarea orientat obiect Programarea orientat pe componente

7 14 12 15 29 * 15

14,25 3,3 15,38 20,08 20,08 35,33 *

n cazul programrii structurate, cele dou variante corespund situaiilor n care programul a fost dezvoltat ca un monolit, respectiv folosind funcii. Componentele sunt vzute ca i cutii negre, astfel c important este funcionalitatea expus i nu implementarea. Componentele pot fi scrise ntr-un limbaj de programare i utilizate n aplicaii dezvoltate folosind alt limbaj de programare. Prin urmare, analiza pe codul componentelor nu are relevan; n plus, n funcie de diferitele tehnologii orientate pe componente, exist elemente suplimentare de cod care apar n dezvoltare. Setul de metrici pentru evaluarea complexitii componentelor nu conine

154

Concluzii

indicatori ce se aplic asupra codului surs, mai ales c acesta poate fi rescris, fr a se afecta utilizarea componentei. Se observ o cretere a complexitii de la abordarea clasic ctre cea orientat obiect, cretere datorat specificitii diverselor tehnici. Diferenele de complexitate nu sunt mari, cel puin n cazul primelor tehnici (clasic, standard, structurat, modular). n cazul tehnologiei orientate obiect, exist un salt semnificativ de complexitate, explicabil prin faptul c exist multe construcii de limbaj care aduc un plus de complexitate (de exemplu, existena constructorilor), dar i prin faptul c metricile alese nu au mare relevan n cazul acestei tehnici de programare. De aceea, n practica curent, se pune accentul pe alegerea unui alt set de metrici atunci cnd se discut despre complexitatea codului surs orientat obiect sau despre complexitatea aplicaiilor bazate pe componente, acest lucru fiind subliniat n capitolele 7 i 8 ale lucrrii. ntr-o analiz de acest tip, important este reprezentativitatea setului de date pe care se face analiza, respectiv codul surs. Analiza efectuat n cadrul lucrrii ofer indicii primare cu privire la relaia dintre complexitate i tehnica de programare folosit la dezvoltarea produsului, ns, pentru o analiz complet, se impune aplicarea acestor metrici pe un lot mai mare de probleme, pentru care s se construiasc variante corespunztoare tuturor tehnicilor de programare prezentate.

155

Anexa 1

P Ai F LAi lg(F) pi ki Di xi S Ij PR L na nn CM n1 n2 CH n fi x[i] xmin pozmin

ei x[N] a[M][N] -

x ik Pi

denumire problem pentru care se dezvolt software element al unei colecii de date (articol) fiier care memoreaz o colecie de date (articole) lungimea n baii a unui element Ai lungimea total a fiierului F, n baii poziia n fiier a unui element Ai cheia elementului Ai deplasarea elementului Ai fa de nceputul fiierului F element al unui ir de numere suma elementelor xi ale unui ir instruciunea de pe poziia j din program program care rezolv o problem dat lungimea n numr de instruciuni a unui program numrul de arce din graful asociat programului PR numrul de noduri din graful asociat programului PR complexitatea software n sens McCabe frecvena operanzilor din program frecvena operatorilor din program complexitatea n sens Halstead numrul de elemente ale unui ir de numere frecvena de apariie a elementului xi n ir elementul de pe poziia i din vectorul x valoarea elementului minim din vectorul x poziia din vectorul x pe care o ocup elementul cu valoarea minim eticheta i din program masiv unidimensional cu dimensiunea maxim N masiv bidimensional cu dimensiunile maxime M linii i N coloane media aritmetic a elementelor unui masiv unidimensional variabil de stare subproblem a problemei P

156

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

SPi Pij in C1 S1 S2 i vinit vfin r S S` C DI DE NE Mij SPi S-SPij

subprogramul corespunztor subproblemei Pi subproblema j a subproblemei Pi numrul de instruciuni dintr-o secven expresie condiional secvena de instruciuni care se execut dac expresia condiional C1 este adevrat secvena de instruciuni care se execut daca expresia condiional C1 este fals variabila de control valoarea iniial a variabilei de control valoarea final a variabilei de control raia secvena de instruciuni care se execut n cadrul structurii repetitive secvena de instruciuni care se execut dup ncheierea execuiei unei structuri repetitive expresia condiional dintr-o secven repetitiv datele de intrare ale problemei datele de ieire ale unei probleme numrul datelor de ieire furnizate de produsul software modulul pentru obinerea outputurilor DEi aflat pe nivelul j, care utilizeaz datele de intrare DEij subproblema i a problemei P subproblema j, a subproblemei i, a problemei P

157

[ATHAN95] Irina ATHANASIU, Eugenia KALISZ, Valentin CRISTEA Iniiere n TURBO PASCAL, Bucureti, Editura Teora, 1995 [BARBU97] Gheorghe BARBU, Ion VDUVA, Mircea BOLOTEANU Bazele Informaticii, Bucureti, Editura Tehnic, 1997 [BUDD97] [CATR94] [CRIST98] Timothy BUDD An Introduction to Object Oriented Programming, Second Edition, Addison-Wesley, 1997 Octavian CATRINA, Iuliana COJOCARU Turbo C++, Bucureti, Editura Teora, 1994 Valeriu CRISTEA, Irina ATHANASIU, Eugenia KALISZ, Valeriu IORGA Tehnici de programare, Bucureti, Editura Teora, 1998 Bodgan GILIC-MICU, Ion Gh. ROCA, Constantin APOSTOL, Marian STOICA, Ctlina COCIANU Algoritmi n Programare, Bucureti, Editura ASE, 2002 Ion Gh. ROCA, Bogdan GHILIC-MICU, Ctlina COCIANU, Marian STOICA, Cristian USCATU Programarea calculatorului. tiina nvrii unui limbaj de programare. Teorie i aplicaii, Bucureti, Editura ASE, 2003 Ion SMEUREANU, Ion IVAN, Marian DRDAL Structuri i obiecte n C++, Bucureti, Editura Cison, 1998 Mark LORENTZ, Jeff KIDD Object-oriented software metrics: a practical guide, Englewood Cliffs, NJ PTR Prentice Hall, 1994 Rodica MIHALCA, Ion IVAN, Ioan ODGESCU Programe applicative, Bucureti, Editura ASE, 1983

[GMICU02]

[GMICU03]

[IVANI98] [LOREN94]

[MIHAL83]

158

Analiza comparat a complexitii entitilor text generate prin tehnici de programare

[MIHAL98]

Rodica MIHALCA, Csaba FABIAN, Adina U, Felix SIMION Analiz i proiectare orientate obiect. Instrumente de tip CASE, Bucureti, Editura Societatea Autonom de Informatic, 1998

[MSPCD97] Microsoft Press Computer Dictionary, Third Edition, Microsoft Press, 1997 [ROCA94] Ion Gh. ROCA, Constantin APOSTOL, Valer ROCA, Bogdan GHILIC-MICU Prelucrarea fiierelor n PASCAL, Bucureti, Editura Tehnic, 1994 Ion Gh. ROCA, Ctlina COCIANU, Cristian USCATU Programarea calculatoarelor. Aplicaii, Bucureti, Editura ASE, 2003

[ROCA03]

[ROCA103] Ion Gh. ROCA, Bogdan GHILIC-MICU, Constantin APOSTOL, Valer ROCA, Ctlina COCIANU Programarea calculatoarelor. Tehnica programrii n limbajul PASCAL, Bucureti, Editura ASE, 2003 [ROTAR96] Eugen ROTARU Limbajul Java, Trgu-Mure, Computer Press Agora, 1996 [SMEU01] [SMEU02] Ion SMEUREANU, Marian DRDAL Programarea n limbajul C/C++, Editura Cison, Bucureti, 2001 Ion SMEUREANU, Marian DRDAL Programarea orientat obiect n limbajul C++, Bucureti, Editura Cison, 2002

[SMEUR04] Ion SMEUREANU, Marian DRDAL, Adriana REVEIU Visual C#. .NET, Bucureti, Editura Cison, 2004 [SPIR95] Claudia SPIRCU, Ionu LOPTAN POO Analiza, proiectarea i programarea orientate obiect, Bucureti, Editura Teora, 1995 Bjarne Stroustrup The C++ Programming Language, Addison Wesley, 1987

[STROU87]

159

S-ar putea să vă placă și