Home - Rasfoiesc.com
Educatie Sanatate Inginerie Business Familie Hobby Legal
Doar rabdarea si perseverenta in invatare aduce rezultate bune.stiinta, numere naturale, teoreme, multimi, calcule, ecuatii, sisteme




Biologie Chimie Didactica Fizica Geografie Informatica
Istorie Literatura Matematica Psihologie

Informatica


Index » educatie » Informatica
» Proiectarea Software - Modele ale proiectarii software


Proiectarea Software - Modele ale proiectarii software


Proiectarea Software -

Introducere

Este esential sa dezvoltam un model pentru sistem, inainte de a incepe sa scriem cod ce va fi folosit pentru controlarea sistemului sau interactiune cu acesta. Modelarea software-ului este probabil partea cea mai grea a proiectarii software. Producerea de design-uri software bune necesita experienta practica considerabila, cu destul de mult feedback asupra calitatii design-ului si cu influentarea design-ului urmatorului sistem software de catre produsele software rezultate anterior.

Privim proiectarea software ca un proces iterativ, cu scopul de imbunatatire a design-ului la fiecare iterare. Scopul acestui curs este de a discuta anumite principii de baza care pot ghida procesul de proiectare software. Aceste principii vor fi ilustrate prin mai multe exemple.



Sunteti cu siguranta constienti ca are loc o schimbare fundamentala in industria software. Exista un accent puternic asupra tehnologiilor orientate pe obiecte si a reutilizarii software. Anumite aspecte ale metodologiei orientarii pe obiecte sunt atat de diferite de aspectele corespondente ale abordarii standard, procedurale ale design-ului software incat ele ar trebui discutate separat.

Totusi, un efort curent considerabil al ingineriei programarii curente este in continuare mult mai concentrat asupra analizei cerintelor, design, implementare, testare si mentenanta programelor care au fost dezvoltate sub o abordare procedurala (mult mai familiara) decat al celor ce folosesc tehnici orientate pe obiecte. Din acest motiv, un inginer software trebuie sa fie familiarizat cu proiectarea ambelor tipuri de sisteme software.

Solutia noastra, corespunzatoare atat ingineriei programarii curente cat si celei prevazute in viitor, este de a utiliza o abordare hibrida care combina componente scrise fie in limbaje procedurale, fie in cele orientate pe obiecte. In fond, un modul software existent care realizeaza bine o anumita cerinta, nu ar trebui respins unor potentiale reutilizari doar pentru ca noua aplicatie este orientata pe obiecte.

Aceasta abordare hibrida este uzuala in cadrul comunitatii de inginerie a programarii si a fost formalizata de mai multe organizatii. Considerati experienta Ministerului de Aparare SUA, care cheltuie sume enorme de bani pentru dezvoltare si mentenanta software. Un studiu de la sfarsitul anilor '70 ilustra ca software-ul este dezvoltat sau mentinut in peste 1600 limbaje si dialecte diferite ale calculatorului. Aceasta a constituit motorul dezvoltarii limbajului de programare Ada, proiectat pentru a face uz de lectiile invatate in numerosii ani de dezvoltare software.

Limbajul Ada a incorporat multe dintre aceste lectii, inclusiv ascunderea informatiei, compilarea separata a interfetelor si comunicatiilor interne software cu ajutorul specificatiilor de pachet si corpuri, suport pentru polimorfism si abstractizare prin "generice" si tipizare tare.

La fel de importanta a fost standardizarea limbajului si validarea compilatoarelor Ada, precum si indeplinirea standardelor de limbaj. Un "mandat Ada" necesita ca toate noile dezvoltari software ale Ministerului de Aparare SUA sa fie realizate in Ada, daca nu existau motive substantiale, bine documentate care sa determine o exceptie a mandatului. (complexitatea limbajului Ada a facut dificila producerea de cod executabil rapid cu prima generatie de compilatoare Ada, si astfel, majoritatea exceptiilor se bazau pe nevoia de eficienta in timpul rularii).

Aproape simultan cu actualizarea limbajului Ada (in 1995) in scopul tintirii aspectelor de eficienta si crestere a suportului pentru dezvoltare software orientata pe obiecte, mandatul Ada a fost modificat pentru a reflecta explozia de produse software de inalta calitate si cantitatile enorme de software deja dezvoltat in limbaje de programare orientate pe obiecte si de alt tip. Importanta marita a produselor COTS si a reutilizarii reiese clar din noul mandat, descris in Tabelul 1.

Restul acestui capitol va fi organizat astfel: mai intai vom prezenta cateva principii de design atat de baza, cat si de scop general. Anumite principii de design se vor baza pe tehnica de baza de potrivire a modelelor software. Scopul este de a reutiliza componentele software la un nivel cat mai ridicat posibil.

Aceasta discutie va fi urmata de anumite reprezentari utilizate in mod uzual pentru proiectarea sistemelor orientate pe proceduri, cu exemple ale fiecarei reprezentari. Dupa finalizarea discutiei initiale asupra proiectarii sistemelor orientate pe proceduri, vom discuta despre software orientat pe obiecte, in aceeasi maniera.

Ultimele trei sectiuni ale cursului vor fi dedicate in primul rand proiectarii exemplului inceput mai devreme, in cursurile anterioare. Acest exemplu va fi discutat in detaliu. Vom pune accent in mod special asupra acelor aspecte care se ridica datorita combinarii necesare a design-urilor procedurale si orientate pe obiecte.

Tabelul 1

Rezumatul celei mai recente versiuni a mandatului Ada pentru sisteme software ale Ministerului Apararii, cu solutiile software preferate ilustrate in ordinea preferintelor.

Sursa: DOD 5000.2-R , articolul 3.5 Software Engineering (Modificare trei, 23 Martie 1998), informatii de pe site-ul web https://sw-eng.falls-church.va.us/dod5000-2.html

Software ar trebui administrat si construit utilizand cele mai bune procese care sunt cunoscute pentru reducerea costului, planificare si riscuri ale performantei. Aceasta este politica M.A. SUA in proiectarea si dezvoltarea sistemelor software bazate pe principiile ingineriei sistemelor (CCA) care include urmatoarele:

Dezvoltarea de arhitecturi a sistemelor software care suporta conceptele open system (sistem deschis, interoperabil); exploatarea sistemelor computer comerciale COTS; furnizarea de imbunatatiri marite bazate pe software modular, reutilizabil si extensibil.

Identificarea si exploatarea posibilitatilor de reutilizare software, administrative si comerciale, inaintea inceperii noii dezvoltari software.

Alegerea limbajelor de programare in contextul factorilor de sistem si a inginerie programarii care influenteaza costurile totale ale ciclului de viata, riscurile si interoperabilitatea potentiala. Informatii suplimentare sunt cuprinse in memorandumul ASD(C31), "Utilizarea limbajului de programare ADA", 29 Aprilie 1997.

Utilizarea datelelor standard ale M.A SUA. Informatii suplimentare sunt cuprinse in DoDD 8320.1;

Selectarea contractorilor cu experienta in domeniu in dezvoltarea sistemelor software comparabile, cu inregistrari de performante de succes anterioare, si capacitate si proces de dezvoltare software demonstrabile si mature.

Utilizarea unui proces de masurare software in planificarea si urmarirea programului software, si pentru evaluarea si imbunatatirea procesului de dezvoltarea software si a produsului software asociat.

Asigurarea evaluarii riscurilor operarii informatiilor (DoDD S-3600) si

Asigurarea ca software-ul este in acord problema Anului 2000.

2. Modele ale proiectarii software

Un posibil mod de proiectare software este sa incercam sa potrivim problema care trebuie rezolvata cu un sistem software deja existent care rezolva acelasi tip de problema. Aceasta abordare reduce cel putin o portiune a proiectarii software la modelul corespunzator. Eficacitatea depinde de un set anterior dezvoltat de    module software si o cale de recunoastere a diferitelor modele.

Urmatoarele reprezinta cateva tipuri de modele care par sa apara incontinuu in dezvoltarea software. Aceste modele (de nivel relativ inalt) sunt:

1. Un sistemul condus de meniuri (menu-driven), in care utilizatorii trebuie sa parcurga prin mai multi pasi intr-o ierarhie cu scopul de a indeplini munca pe care el sau ea vrea sa o efectueze. Meniurile poate de tipul "trage-jos" (pull-down), uzuale in cazul calculatoarelor personale, sau pot fi in intregime bazate pe text.

2. Un sistem condus de evenimente (event-driven), in care utilizatorii trebuie sa selecteze pasii in scopul efectuarii muncii pe care el sau ea doreste sa o execute. Pasii nu trebuie sa fie facuti intr-o ordine ierarhica. Acest model este cel mai uzual intalnit in controlul proceselor concurente, cand actiunile se pot repeta in mod nedefinit, in contrast cu modelul numarul 3. Este de asemenea tipicul unei interfete cu utilizatorul ghidate prin selectarea optiunilor din meniuri si combinatii de taste, precum meniuri care apar (pop-up) ca raspuns la cererile utilizatorului. In orice caz, este mai putina ierarhie ca in modelul anterior.

3. Un sistem in care actiunile intreprinse depind de o anumita stare dintre un numar mic de stari si de un set mic de actiuni optionale care pot fi intreprinse pentru fiecare stare. Actiunea optionala intreprinsa depinde atat de starea cat si de valoarea unui cadru de control de intrare (input token). In acest model cadrele de intrare sunt in mod obisnuit prezentate ca flux. O data ce un cadru de intrare este procesat, acesta este indepartat din fluxul intrarilor.

Un sistem in care este procesata o secventa de cadre de intrare (de obicei in format text), cate un cadru de intrare o data. Acest model difera de modelele anterioare prin faptul ca decizia referitoare la actiunea intreprinsa poate sa depinda de mai multa informatie decat disponibila din perechea constituita de stare si cadrul de intrare. In acest model, cadrele de intrare pot sa ramana in fluxul de intrari si in urma procesarii.

5. Un sistem in care este cautata una sau mai multe informatii specifice in cadrul unei cantitati mari de informatie. Cautarile pot sa apara de una sau de mai multe ori.

6. Un sistem care poate fi utilizat in diferite aplicatii, dar care trebuie ajustat pentru a functiona corespunzator pentru noi setari.

7. Un sistem in care totul este ghidat primordial de un algoritm, mai degraba decat dependenta primordiala de date.

8. Un sistem distribuit, cu mai multe actiuni de procesare relativ independente care sunt intreprinse. Cateva dintre actiunile de procesare pot comunica cu alte actiuni de procesare.

Cate dintre aceste modele va sunt familiare? Primele doua descriu interfetele om-calculator,    prima fiind un sistem rigid codus de meniuri, iar cealalta fiind controlata de actiuni precum deplasarea unui mouse sau a altor pointeri si apasarea unui buton.

Modelul software numarul trei descrie ceea ce este deseori cunoscut ca "masina starii finite" sau "automat finit determinist". Acest model este in mod special folositor in controlarea unor procese in intreprinderi de productie.

Modelul numarul 4 apare folosit deseori in software-ul utilitar. Reprezinta baza pentru analizatorii lexicali si pentru actiunile analizei sintactice a compilatoarelor. Multe sisteme software prezinta o anumit analiza sintactica pentru procesarea comenzilor de intrare.

Evident, modelul software numarul 5 se refera la    problema cercetarii bazei de date.

Modelul numarul 6 este unul general, dar care sugereaza ca exista un sistem scop-general care trebuie configurat special pentru fiecare setare a aplicatiei. Instalarea unei imprimante pentru un calculator personal (sau o retea de calculatoare) urmeaza acest model.

Modelele software 7 si 8 sunt de asemenea foarte generale. Totusi, modelul 7 pare sa sugereze ca solutia va avea o natura procedurala, in timp ce modelul 8 ar putea fi mai potrivit unei solutii care utilizeaza metode orientate pe obiecte.

Aceste modele software nu reprezinta reguli absolute. Nici nu sunt intentionate drept clasificare completa a software-ului. Totusi, ele ne pot ghida in proiectarea si implementarea portiunilor procesului de dezvoltare software.

Remarcam explicit ca nu este necesar ca intregul sistem software considerat sa se potriveasca cu unul dintre modele de mai sus. Este perfect rezonabil sa avem diferite portiuni ale aceluiasi sisteme software care sa se potriveasca mai multe modele diferite. Este cazul intalnit atunci cand vom discuta exemplul proiectului nostru major, mai tarziu in acest capitol.

Separarea unui sistem software in mai multe subsisteme este uzuala in timpul proiectarii software. Intr-adevar, un fel de imbunatatire pas cu pas a design-urilor este esentiala pentru un proces de proiectare software eficient. Descompunerea    design-ului sistemului va fi o tema repetata de-a lungul acestui curs. Pentru moment, vom ignora descompunerea sistemului si ne vom indrepta atentia asupra modelelor software.

Sa luam in considerare modul in care pot fi folosite aceste modele ca parte a procesului de proiectare. Presupunem ca am recunoscut un model particular ca fiind aplicabil sistemului software pe care trebuie sa il proiectam. In ce directie ne indreptam acum?

Primul pas este de a vedea daca putem sa ne facem munca mai usoara. Mai exact, ar trebui sa cautam in cadrul software-urilor disponibile pentru a determina daca, nu cumva avem deja o solutie partiala sau completa a problemei. Aceasta situatie este un exemplu de reutilizare software, reprezentand cea mai eficienta cale de a produce software. Daca software preexistent rezolva exact problema, atunci am terminat. Modificarile necesare ar trebui comparate cu costul estimat al unui software nou in intregime, pentru a putea vedea daca ar trebui sa incercam sa reutilizam o potrivire partiala. Vom ilustra aplicarea reutilizarii software in cadrul discutiilor referitoare la proiectul major software in sectiunea 16 a acestui curs.

3 Introducere in reprezentarile design-ului software

Orice notatii, tehnici sau instrumente care ne pot ajuta sa intelegem sistemele sau sa le descriem ar trebui sa fie luate in considerare in mod serios de catre persoana care modeleaza sistemul. In aceasta sectiune ne vom concentra toata atentia asupra tehnicilor de modelare si vom discuta pe scurt notatiile folosite in proiectare.

Presupunem ca nu gasim un software existent care poate fie sa rezolve direct problema, fie sa reprezinte o solutie candidat dupa ce a fost modificat. In acest caz, suntem obligati sa proiectam software nou pentru a rezolva problema. Cum vom face aceasta?

Exista diverse moduri de descriere a sistemului software:

Software-ul poate fi descris prin fluxul de control al sistem

Software-ul poate fi descris prin fluxul datelor in cadrul sistem

Software-ul poate fi descris prin actiunile intreprinse de sistem

Software-ul poate fi descris prin obiectele actionate de catre sistem

Prima descriere a software-ului ne conduce la conceptul de graf al fluxului. Primele reprezentarile grafice populare ale design-urilor se numeau fluxuri grafice, fiind orientate pe fluxul de control. Termenul de "flux de control" este o metoda de descriere a unui sistem cu ajutorul blocurilor majore de cod care controleaza operatiile acestuia. In anii '50-'60, un flux grafic se trasa general manual, folosindu-se o notatie grafica ce prezenta controlul programului ca si capete ale unui graf directionat ce descria programul.

Nodurile unui graf flux de control erau casute ale caror forma si orientare oferea informatii aditionale despre program. De exemplu, o casuta dreptunghiulara cu margini orizontale sau verticale simbolizeaza un proces de calcul care apare in punctul respectiv in cadrul programului. O casuta in forma de diamant, cu margini la un unghi de 45° fata de orizontala, se numeste "bloc de decizie". Acesta reprezinta o ramificare in fluxul de control al programului. Se mai utilizeaza si alte simboluri pentru a reprezenta situatii ce apar in mod uzual in comportamentul programului. Un exemplu de graf pentru fluxul de control al unui program ipotetic este prezentat in Figura 1.


Figura 1. Descrierea unui grafic flux de control pentru un program ipotetic

Asa cum am indicat, exista multe simboluri care pot fi folosite in grafurile flux de control. Unealta de desenare din Microsoft Word are 28 de icoane predefinite care reprezinta diferite simboluri utilizate de obicei in cadrul grafurilor flux de control. Cinci dintre acestea sunt ilustrate in Figura 2.


Figura 2. Cateva simboluri folosite uzual in grafice flux de control. Citite in sensul acelor de ceasornic, din partea stanga-sus, simbolurile sunt: "proces", "date", "proces predefinit", "date interne", si "document"

A doua metoda de descriere a design-urilor corespunde reprezentarii fluxului de date a software-ului. Asa cum am mentionat in Cursul 1, reprezentarile fluxurilor de date ale sistemelor au fost dezvoltate ulterior descrierilor pe baza fluxului de control.

Din moment ce date diferite se pot deplasa pe cai diferite in cadrul programului, este uzual ca descrierile de design pe baza fluxului de date sa includa numele datelor pe langa sagetile ce indica directia deplasarii datelor. Exista diferite notatii ce sunt utilizate pentru diferite tipuri de tratare a datelor. De exemplu, un nod al grafului reprezentand o transformare a datelor de intrare in date de iesire pe baza unei anumite reguli ar putea fi reprezentat printr-un bloc dreptunghiular. O sursa de date de intrare ale unui flux (stream), precum un terminal de intrare interactiv, ar fi reprezentat printr-o alta notatie, indicand faptul ca acesta este o "sursa de date". Pe de alta parte, un depozitar din care datele nu mai pot fi recuperate, precum un terminal ecran, este descris printr-un alt simbol, indicand faptul ca aceasta este o "scurgere de date".

Descrierile tipice ale fluxului de date folosesc diverse diagrame, pe niveluri diferite. Fiecare nivel al unei diagrame a fluxului de date reprezinta o viziune mai detaliata a unei portiuni a sistemului descrise anterior la un nivel mai inalt. O viziune la nivel foarte inalt a analizei preliminare a fluxului de date intr-un program ipotetic este ilustrata in Figura 3. Aceasta diagrama simpla ar fi probabil numita "diagrama a fluxului de date pe nivelul 1", unde nivelul 0 ar consta din simpla reprezentare a intrarilor si iesirilor.


Figura 3. Descrierea de nivel 1 a diagramei unui flux de date (DFD) pentru un sistem ipotetic

A treia metoda de reprezentare a design-ului unui sistem software este in mod clar cea mai potrivita pentru o viziune orientata pe proceduri a sistemului. Ea poate include fie flux de control, fie flux de date, sau chiar descrieri combinate ale software-ului. Notatiile folosite pentru aceasta abordare hibrida nu sunt standard, Un astfel de design poate fi la fel de simplu precum, de exemplu, un bloc din Figura 1. etichetat "Pas 1", pana la graficul flux descris in Figura 3.

In final, cea de-a patra metoda este in mod clar cea mai potrivita unei viziuni orientate pe obiecte a sistemului. Aceasta este evident o paradigma diferita de cele anterioare. Am ales sa folosim o reprezentare modelata, cunoscuta drept UML (Unified Modeling Language). UML este o tentativa de descriere a relatiilor intre obiectele unui sistem, fara a descrie fluxul de control sau transformarile directe ale datelor.

Remarcati ca fiecare bloc ilustrat in Figura 4 reprezinta un obiect pentru care structura de mostenire este in mod clar indicata de directia sagetii: obiectul de tipul Clasa 1 este o superclasa a obiectului de tipul Clasa 3. Intr-un design real ce foloseste modelul obiectual unificat, linia orizontala ar contine informatii despre tipul de relatie (unu-la-unu, multe-la-multe, unu-la-multe) si despre agregarea unor obiecte multiple intr-un singur obiect. Omitem aici aceste detalii.


Figura     O descriere orientata pe obiecte ultra-simplificata a unui sistem ipotetic, folosind notatia UML

Este deseori foarte dificil pentru un inginer software incepator sa determine obiectele corespunzatoare design-ului sistemului software. Cu toate ca exista putine cercetari comparative pentru a sprijini ipoteza ca un design bun orientat pe obiecte este mai greu de creat decat unul care foloseste abordarea traditionala, orientata pe proceduri, consideram totusi ca este nevoie de antrenament considerabil pentru a putea aprecia subtilitatile abordarii orientate pe obiecte. Studentul nefamiliarizat cu abordarea orientata pe obiecte este incurajat sa citeasca acestea si orice discutii inrudite din cadrul cartii, pana se familiarizeaza total cu dezvoltarea software, pentru a intelege de ce au fost luate anumite decizii.

O abordare ajutatoare este de a gandi descrierea functionalitatii unui sistem cu propozitii complete. Verbele propozitiilor sunt actiuni ale sistemului; substantivele reprezinta obiecte. Vom folosi aceasta abordare simpla atunci cand vom dezvolta acea portiune a design-ului proiectului nostru major de inginerie software, pentru care are sens abordarea orientata pe obiecte.

Este normal ca studentul incepator sa se intrebe pentru ce sunt necesare abordari multiple ale reprezentarii design-ului. Bineinteles ca anumite tehnici au fost dezvoltate din motive istorice. Totusi, multe tehnici si reprezentari au supravietuit pentru ca au oferit viziuni alternative utile ale design-ului software.

Familiara problema a sortarii unei matrici ofera o ilustrare buna a deosebirilor celor patru abordari. Sa consideram arhi-cunoscutul algoritm quicksort, dezvoltat de C.A.R. Hoare.

Algoritmul Quicksort partitioneaza o matrice in doua submatrici de marimi poate diferite. Cele doua submatrici sunt separate de un element "pivot", care este cel putin la fel de mare ca toate elementele dintr-o submatrice, si nu este mai mare decat nici un element al celeilalte submatrici. Fiecare submatrice este apoi supusa aceluiasi procedeu. Procesul se incheie cu o matrice complet sortata. Remarcati ca descrierea acestui algoritm este recursiva. Ganditi-va ca algoritmul Quicksort este folosit intr-un design ce trebuie sa indeplineasca anumite cerinte de sortare eficienta a unui set de date de marime necunoscuta.

O descriere a fluxului de control a algoritmului ar conduce la un design puternic dependent de descompunerea logica a logicii programului. Ganditi-va la implementarea algoritmului Quicksort recursiv intr-un limbaj precum FORTRAN sau BASIC, care nu suporta recursivitatea. Logica design-ului ar fi cea mai importanta. Pe de alta parte, seturi de date prea mari ar putea determina mult prea multe niveluri de apeluri de functii recursive, daca se foloseste un algoritm pur recursiv. Aceasta viziune bazata pe fluxul de control ar putea scoate la iveala anumite limitari ale design-ului unui algoritm Quicksort recursiv simplu.

O descriere a fluxului de date a algoritmului ar accentua deplasarea datelor intre matrici si cele doua submatrici de dimensiune mai mica ce sunt create la fiecare iterare a algoritmului Quicksort. Atentia la detaliile rezervarii locatiilor de stocare pentru aceste submatrici ar putea duce la luarea in considerare a situatiei in care nu exista suficient spatiu de memorie.

A treia viziune poate fi obtinuta prin luarea in considerare a unei solutii pur procedurale. In acest caz poate fi folosita o functie de biblioteca standard. De exemplu, biblioteca standard C are o functie numita qsort(), care primeste ca argument o matrice si produce o matrice sortata in aceeasi locatie. Cu alte cuvinte, matricea de intrare este suprascrisa de matricea de iesire.

Utilizatorul functiei qsort() din biblioteca standard C trebuie sa ofere o functie de comparatie pentru a realiza comparatii intre elementele matricei. Prototipul acestei functii de comparatie este ilustrat mai jos:

int * compare(* element1, * element2);

Aceasta functie de comparatie definita de utilizator primeste doua argumente (care reprezinta elemente arbitrare ale matricei) si returneaza 0 daca cele doua argumente sunt egale. Functia de comparatie returneaza -1 daca primul argument este mai mic decat al doilea, si 1 altfel. Numarul de elemente ale matricei si marimea unui element al matricei trebuie furnizate si ele.

Functia qsort() din biblioteca standard C se poate accesa daca se include fisierul antet stdlib.h in cadrul programului C. Aceasta functie are sintaxa:

void qsort(

const void * base,

size_t num_elts,

size_t elt_size,

int (*compare(const void *, const void *)

);

si utilizarea ei tipica este:

ptr = qsort(arr, num_elts, elt_size, compare);

In final, o abordare orientata pe obiecte ar utiliza cel mai probabil o clasa generala pentru matricea de elemente, si ar invoca o functie membru standard pentru sortare. O asemenea functie s-ar gasi in mod uzual intr-o clasa biblioteca a unei clase abstracte. Un exemplu pentru acestea poate fi gasit in bibliotecile claselor oferite cu majoritatea sistemelor de dezvoltare C++.

O clasa generala intr-un sistem orientat pe obiecte va contine metodele care pot fi aplicate obiectului reprezentat de clasa. In C++, metodele asociate cu un obiect se numesc "functii membre" ale clasei. In cazul C++, o descriere de clasa va contine probabil "template-uri", sau clase generalizate in care tipul specific al unui membru al clasei este relevant abia in momentul utilizarii clasei. Astfel, o clasa template poate referi o matrice abstracta de intregi, siruri de caractere, sau alte tipuri relevante pentru care operatiile clasei au sens.

Presupunand ca metodele unei clase template pot fi implementate pentru un anumit tip de obiect al clasei, metoda generala cunoscuta drept sortare poate fi invocata prin simpla apelare a unei functii membre, de exemplu:

A.sort();

Aici, tipul obiectului A este compatibil cu tipul template-ului, si se foloseste functia membru sort() a acelui obiect.

Chiar si pentru cazurile simple de algoritmi de sortare am vazut mai multe abordari diferite ce pot fi folosite pentru design-ul sistemului software. Fiecare prezinta avantaje si dezavantaje. Nu am analizat in detaliu nici unul dintre dezavantaje. In special, nu am luat niciodata     in considerare problema eficientei unui software scris in concordanta cu unul dintre design-urile descrise anterior. De exemplu, un algoritm de sortare lent, sau unul care foloseste recursivitatea, poate fi total neadecvat pentru multe aplicatii software.

Exista o metoda folosita in mod uzual pentru descrierea unui sistem. Aceasta implica pseudocod care ofera o descriere a sistemului aproape in limba engleza (pentru mediile de dezvoltare software care folosesc limba engleza). Pseudocodul este imbunatatit succesiv pana la implementarea unui cod sursa de incredere, cel putin teoretic. Remarcati ca pseudocodul este o notatie non-grafica. Un exemplu de pseudocod este ilustrat in Exemplul 1. Acesta descrie o portiune a unui sistem de autentificare, de protectie a parolelor intr-un sistem ipotetic.

GET login_id as input from keyboard

Compare Input to entries in login_id database

IF not a match THEN

WAIT 10 seconds

SET error_count to 1

REPEAT

PROMPT user for new login_id

IF login_id matches database

THEN PROMPT for password

ELSE increment error_count

WAIT 10 seconds

END IF

IF error_count > 3 EXIT password PROMPT

END REPEAT

ELSE

GET password as input from keyboard

Compare password entries in password database

IF error THEN

EXIT

ELSE

BEGIN login process

END IF

Exemplul 1 O descriere pseudocod a unui sistem ipotetic

Reprezentarile pseudocod au doua avantaje majore fata de cele grafice: pot fi prezentate ca informatie textuala in fisiere ASCII, si descrierile pseudocod ale sistemelor mari nu sunt cu nimic mai complicate de reprezentat decat cele ale sistemelor mici. Bineinteles, reprezentarile pseudocod pot fi atat de mari si pot avea atat de multe nivele de imbricare a instructiunilor, incat sa devina greu de inteles.

Ar trebui sa remarcati un alt avantaj al reprezentarilor pseudocod folosite pentru design:     ele pot produce documentatie interna instantanee a fisierelor cu cod sursa.

Reprezentarile design-urilor descrise in aceasta sectiune nu epuizeaza insa numeroasele reprezentari disponibile. Alte reprezentari uzuale folosite includ diagramele Buhr, diagramele Booch, schemele HIPO si schemele Nassi-Schneiderman. Diagramele Booch pot fi folosite foarte usor pentru sistemele orientate pe obiecte, in timp ce majoritatea altor reprezentari nu pot. Descrierea fiecareia poate fi gasita in diverse carti de inginerie a programarii si in unele scrieri originale ale inventatorilor acestor notatii.

4 Reprezentarile design-ului orientat procedural

In aceasta sectiune vom oferi exemple ale utilizarii diferitelor reprezentari ale design-ului orientat pe obiecte pentru cazul unui sistem singular. Vom considera cazul aceluiasi sistem pentru exemplificarea reprezentarilor design-ului orientat pe obiecte (in Sectiunea 9).

Consideram o situatie familiara: software care controleaza un concentrator de terminale, adica un dispozitiv hardware care permite mai multor linii de terminal sa acceseze acelasi CPU. Intrarea de la o linie terminal este asociata cu terminalul la care este atasata la capat linia. Iesirea corespunzatoare pentru un program ce ruleaza pe unul dintre terminale este trimisa de la CPU la terminalul de ecran corespunzator.

Pentru a evita ca datele trimise la si de la terminale diferite sa ajunga in alt loc decat cel menit, semnalele sunt "multiplexate" de concentratorul de terminale. Hardware si software pentru multiplexare permit atasarea unor terminale multiple la acelasi port al computerului, permitand astfel un numar mai mare de utilizatori simultan (cu costul potential al reducerii vitezei de procesare). Toate terminalele de pe un concentrator de terminale partajeaza aceeasi conexiune cu computerul, asa cum se arata in Figura 5.


Figura 5. Un concentrator de terminale. Sursa: Leach, Proiectare si programare orientata pe obiecte in C++, Academic Press, 1995

Multiplexarea inseamna ca se foloseste un singur set de cabluri pentru conectarea de la concentratorul de terminale la CPU. Decizia referitoare la care va fi terminalul cu care se face comunicarea prin aceste cabluri poate fi luata utilizand diferite frecvente pentru semnale sau prin atasarea informatiei de rutare la fiecare pachet de informatie trimisa.

Structura de date de baza intr-un sistem multiplexat este coada. Datele unui utilizator sunt trimise de la terminalul lui la CPU printr-un stream, in maniera primul-intrat-primul iesit. Datele parcurg operatia de multiplexare a concentratorului de terminale si sunt trimise la CPU atunci cand procesul este planificat pentru executie. Toate celelalte procese (si I/O de la terminalele lor) asteapta ca procesul sa predea controlul CPU-ului. Datele de iesire sunt apoi trimise de la CPU la terminalul corespunzator, de asemenea cu ajutorul operatiei de multiplexare a concentratorului de terminale.

Astfel, exista cozi de intrare, cozi de iesire si mecanisme de determinare a caror date sunt atasate carui terminal (fie pentru intrare, fie pentru iesire).

O schema a fluxului software-ului care controleaza un concentrator de terminale este ilustrata in Figura 6. Ar trebui sa comparati aceasta figura cu exemplul de pseudocod pentru sistemul concentrator de terminale, ilustrat in Exemplul 2.

Figura 6. Flux de control pentru un concentrator de terminale. Sursa: Leach, Proiectare si programare orientata pe obiecte in C++, Academic Press, 1995

Un exemplu de descriere a fluxului de date a unui program este notatia grafica din Figura 7. Diagrama fluxului de date ilustrata in aceasta figura descrie o directie a fluxului pentru exemplul concentratorului de terminale descris anterior. Sistemul concentratorului de terminale poate fi descris complet printr-o diagrama mai elaborata.

Figura 7. Reprezentarea fluxului de date pentru un concentrator de terminale.

For each terminal

When time for output from CPU

Exemplul 2. O reprezentare pseudocod pentru un concentrator de terminale

In realitate, schimbarile de tehnologie si rasturnarea rapida din industria de inginerie a programarii presupun ca un proiectant software sa fie familiarizat cu mai multe reprezentari diferite ale design-ului.

Modelul entitate-relatie, sau E-R, este uzual design-ului bazelor de date. Altul este modelul informatie, frecvent utilizat in sisteme de inteligenta artificiala si sisteme expert.

O diagrama E-R reprezinta un set de cantitati fundamentale, cunoscute ca entitati, si relatiile dintre acestea. Etichetarea arcelor din diagrama E-R indica natura relatiilor dintre entitatile conectate de aceste arce.

Diagrama E-R poate servi ca punct de pornire pentru un set preliminar de obiecte. Relatiile diagramelor sugereaza deseori metode posibile, sau transformari, ale obiectelor din sistem.

Aceasta metoda este doar un prim pas in dezvoltarea unei descrieri complete a obiectelor si metodelor unui sistem, deoarece diagrama E-R nu prezinta de obicei auto-transformari ale unui obiect. Astfel, constructorii, destructorii si initializatorii nu sunt de obicei evidenti in diagramele E-R. Testele de egalitate sunt in mod normale neclare. Si multe alte metode uzuale sunt greu de reprezentat in diagramele E-R.

Observatiile utilitatii diagramelor E-R in obiecte pot fi sumarizate astfel:

Daca exista deja o diagrama E-R, se utilizeaza entitatile ca alegeri initiale pentru obiecte si metode. Trebuie avut grija in mod special la nevoia de metode de auto-transformare, precum constructori, destructori si initializatori.

Daca nu exista o diagrama E-R, nu va deranjati cu a realiza una. In schimb, continuati cu descrierea obiectelor utilizand direct procesul din Tabelul 2.

5 Arhitecturi software

Termenul "arhitectura software" a fost folosit in multe moduri diferite, deseori contradictorii, in comunitatea inginerilor software. Indiferent de contextul specific, termenul este utilizat de obicei pentru a descrie organizarea sistemelor software.

Definim dupa cum urmeaza: o "arhitectura" este definitia elementelor cheie care constituie un sistem, a relatiilor lor si a oricaror constrangeri. Vom vedea ca arhitecturile sunt constituite din mai multe tipuri, fiecare tip reprezentand la randul lui o arhitectura. Folosim abordarile Ezran, Morisio si Tully in descrierea si clasificarea tipurilor de arhitecturi.

In general, arhitecturile sistemelor bazate pe software pot fi clasificate in mai multe categorii:

O arhitectura de afaceri care descrie structura sarcinilor de afaceri realizate de organizatie si mecanismele prin care sistemul suporta aceste sarcini. Descrierea arhitecturii business este deseori creata de un analist in domeniul afacerilor, expert in acest domeniu.

O arhitectura fizica descrie structura platformelor hardware sau a retelelor pe care va opera sistemul.

O arhitectura logica descrie structura obiectelor aplicatie si de afaceri. Aceasta arhitectura este deseori parte a unei viziuni orientate pe obiecte a unui sistem. Corespunzator, descrierea arhitecturii logice este deseori creata de un analist de obiecte cu experienta in tehnologiile obiectuale.

O arhitectura functionala descrie structura cazurilor posibile de utilizare si cerintele, din punctul de vedere al utilizatorului. Din nou, aceasta arhitectura este deseori parte a unei viziuni orientate pe obiecte a sistemului.

O arhitectura software descrie structura sistemului pe straturi, precum modelul OSI cu sapte niveluri ale comunicatiilor de date sau arhitectura stratificata a sistemului de operare UNIX (vezi Figura 8 pentru o viziune a arhitecturii pe niveluri UNIX). O decizie de descompunere a sistemului in client si server ar fi parte a unei arhitecturi software.

O arhitectura tehnica descrie structura interfetelor majore a arhitecturii software. Elemente ale unei arhitecturi tehnice includ interfetele de programare a aplicatiilor (API), produse program de intermediere (middleware), sisteme de management a bazelor de date, interfete grafice cu utilizatorul si alte produse de "lipire" sau "punte" necesare pentru interfatarea componentelor de pe diferite niveluri ale arhitecturii software. Decizii de a utiliza CORBA, DCOM, Java RMI, sau RPC s-ar reflecta intr-o arhitectura sistem de acest tip.

O arhitectura sistem descrie structura afacerii, a aplicatiei, a scopurilor tehnice si relatiile acestora. Descrierea arhitecturii unui sistem este deseori realizata de un analist de sisteme.

O arhitectura a aplicatiei (deployment architecture) descrie structura de mapare a sistemului si arhitecturilor tehnice in arhitecturi fizice. Arhitectura aplicatiei include o viziune statica a fisierelor de baza care vor fi necesare, si o viziune dinamica a proceselor concurente si firelor (thread), si mecanismele pentru sincronizarea si comunicarea acestora. Deciziile de plasare a unui fir pe un anumit computer, sau de a avea un agent autonom care realizeaza operatii de calcul pe un procesor inactiv, ar fi s-ar reflecta intr-o arhitectura de acest tip.

De ce sunt importante arhitecturile? Succesul modelului OSI si a sistemului de operare UNIX ilustreaza puterea abordarii pe nivele a arhitecturii software. Alte tipuri de arhitectura reprezinta tentative de crestere a nivelului de reutilizare in sisteme, prin incurajarea descrierii sistemelor la nivele diferite de detaliere si abstractizare.

Arhitectura stratificata a sistemului de operare UNIX este ilustrata in Figura 8. Arhitectura arata clar ca, de exemplu, apelurile sistem interactioneaza cu nucleul UNIX prin intermediul "vectorului syscall", ca nucleul UNIX interactioneaza cu hardware-ul prin intermediul driverelor de dispozitiv, samd.

Ar trebui remarcat faptul ca utilizarea unei notatii precum UML (Limbaj de Modelare Unificat) poate promova consistenta printre diferitele viziuni arhitecturale. Fie ca aceasta consistenta poate fi incorporata in unelte CASE si procese de dezvoltare intr-o asemenea maniera incat eficienta sa fie imbunatatita, ramane de vazut, cu toate ca eforturile preliminarii sunt promitatoare.

In acest punct, ne vom multumi cu aceasta descriere de nivel inalt a diferitelor tipuri arhitecturale. Ne vom intoarce la descrierile lor atunci cand vom ilustra proiectarea proiectului nostru software major in sectiunea 17.


Figura 8. Arhitectura pe nivele a sistemului de operare UNIX. Sursa: Leach, Aspecte avansate in UNIX, John Wiley, 1994

6 Principii de proiectare software pentru programe orientate pe proceduri

Inainte de a incepe sa studiem in detaliu reprezentarile proiectarii software, vom introduce un element de realitate in discutie. Consideram cazul unui program de aproximativ 500 linii de cod, cu poate sapte sau opt functii. O viziune de nivel inalt a design-ului programului pare sa fie relativ mica, indiferent de tehnica sau reprezentarea de design folosita. Este probabil ca o viziune completa rezonabila a design-ului sa incapa pe o singura pagina. In mod clar, oricare dintre reprezentarile de design descrise mai devreme in acest curs ar putea fi folosite daca sistemele nu sunt prea complicate.

Nu ar trebui sa ne asteptam ca acesta sa fie cazul programelor realiste, utilizate in industrie sau administratie. Evident, design-ul unui program cu 500.000 linii de cod, peste 2000 functii si flux de control si de date complex, nu poate fi reprezentat corespunzator pe o singura pagina de hartie. Astfel, fiecare tehnica de reprezentare a proiectarii va include anumite metode de descompunere a design-ului in unitati mai mici care sunt legate impreuna.

Un exemplu a acestei abordari cu descompunere: diagrama din Figura 9, preluata dintr-o unealta CASE numita Technology for the Automatic Generation of Systems (TAGS, sau Tehnologie pentru Generare Automata a Sistemelor), oferita de Teledyne Brown Engineering. Versiunea prezentata aici este o versiune publica a uneltei de interfatare implementata pentru Macintosh. Aceasta interfata continea doar portiunea de reprezentare a design-ului pentru tot software-ul. Folosea un limbaj special de descriere a sistemului IORL (Input Output Requirements Language - Limbaj de Cerinte Intrare Iesire). Trasaturi ale uneltei CASE complete includeau verificari de consistenta ale design-elor reprezentate grafic, precum si o posibilitate de generare cod care permitea generarea de cod sursa din descrierea grafica a sistemului.

In Figura 9 vom prezenta doar un exemplu al reprezentarii descompunerii. Aceasta figura descrie interactiunea dintre versiunea Macintosh a lui TAGS (numita MacTAGS) si sistemul de operare Macintosh (MacOS) si cutia de instrumente (toolbox) Macintosh, care contine cateva rutine pentru accesarea utilitatilor grafice Macintosh.

Nu are rost sa discutam in detaliu Figura 7. Totusi, exista anumite aspecte care trebuie remarcate. Casutele sunt conectate cu sageti clar trasate. Este evident ca aceasta s-a facut automat, mai degraba decat cu ajutorul unui simplu pachet de desenare. Sagetile sunt etichetate, oferind mai multe informatii despre interfetele casutelor legate de sageti. Etichetele de pe sageti indica numarul interfetei.

Remarcam ca aceasta unealta CASE este mai mult decat un ajutor de desenare ce ofera o reprezentare grafica a software-ului. Include de asemenea un "editor de context" in sensul ca printr-un dublu clic pe oricare dintre sagetile de interfata sau bloc blocuri cu etichete se ofera acces la informatii detaliate suplimentare, precum creatorul casutei sau interfetei, datele ce trec prin interfata intre diferite blocuri, samd. Aceasta tehnica deosebit de folositoare este similara cu a face clic pe un URL intr-un document mail, cand software-ul de mail Eudora va deschide automat o copie a navigatorului de retea asociat. Aceeasi abordare functioneaza de asemenea si pentru alte aplicatii asociate cu un anumit tip de fisier, precum:

https:// document WWW

.doc document Microsoft Word

.xls document Microsoft Excel

.ppt document Microsoft Power Point

.wp document WordPerfect

.exe fisier executabil MS-DOS

Unealta este chiar mai avansata, asa cum se poate vedea din interconectarea prin retea a software-ului cu alte versiuni. Versiunile avansate ale software-ului pentru retele includ un generator de cod optional, astfel ca poate fi folosita si o reprezentare grafica corecta a proiectului pentru a genera cod sursa pentru software-ul care se proiecteaza. Chiar daca codul sursa generat de aceasta unealta nu este complet sau nu indeplineste cerintele de performanta corespunzatoare, codul sursa produs poate economisi un timp de dezvoltare considerabil.


Figura 9. Un exemplu de reprezentare a proiectului cu ajutorul unei unelte CASE

Revenim acum la studiul descompunerii. Scopul descompunerii proiectului este de a produce un proiect detaliat dintr-unul de nivel foarte inalt. Cat de detaliat ar trebui sa fie un document de proiect detaliat? Ar trebui sa fie suficient de detaliat incat sa permita unuia sau mai multor ingineri software sa implementeze cod sursa doar pe baza acestui document. Codul sursa ar trebui implementat neambiguu, in sensul ca variatii minore ale detaliilor de implementare sa ramana consistente cu design-ul.

Din pacate, nu este foarte bine inteles modul in care alegerea unei reprezentari a proiectului conduce la o anumita descompunere a unui proiect de nivel foarte inalt intr-un proiect mai detaliat. De exemplu, descompunerea unui sistem pe baza analizei fluxului de control ar conduce in mod natural la o descriere a actiunilor intreprinse de sistem.

Pe de alta parte, o tehnica de descompunere bazata pe reprezentarea fluxului de date ar conduce la o descriere detaliata a deplasarii datelor ce are loc in sistem. Transformarile datelor sunt usor de detectat intr-o reprezentare detaliata, bazata pe curgerea datelor.

Alte reprezentari ale proiectului influenteaza diferit abordarea descompunerii proiectului. Efectul pseudocodului, a diagramelor de stare si retelelor Petri vor fi discutate in exercitii.

In mod clar, reprezentari diferite ale proiectarii si diferite strategii de descompunere au o influenta majora asupra posibilului proiect detaliat. Bineinteles, exista variatii considerabile de la un proiectant la altul; proiectantii care lucreaza independent vor produce de asemenea proiecte detaliate diferite ale aceluiasi sistem. Astfel, este deseori important pentru management sa realizeze analize comparative ale proiectelor (design-urilor).

Privim pasul descompunerii drept unul care trebuie examinat pentru a ne asigura ca proiectul rezultant este modular, eficient si, mai presus de toate, ca indeplineste cerintele sistemului. Probabil ca nici nu mai trebuie mentionat ca proiectul detaliat trebuie verificat in vederea consistentei cu matricea de urmarire a cerintelor, pentru a ne asigura ca cerintele pot fi indeplinite de o implementare bazata pe design.

7 Ce este un Obiect?

In aceasta sectiune, vom oferi cateva reguli de determinare a obiectelor care sunt prezente in sistemul pe care dorim sa il proiectam. Ideea de baza este ca un obiect are atribute si ca in orice instanta a unui obiect, aceste atribute vor avea valori.

Presupunem ca ati ales un candidat pentru un obiect al sistemului, si ca ati determinat un set de atribute si setul posibil de valori al acestora. Ce teste informale puteti aplica pentru a fi siguri ca obiectele Dvs. sunt cele mai potrivite abstractizari pentru sistem?

Primul test este "testul exemplelor multiple". Afirmat mai simplu, daca exista un singur exemplu al instantei unui obiect, atunci conceptul nu este suficient de general pentru a folosi tehnici orientate pe obiecte pentru implementarea lui.

Testul exemplelor multiple este consistent cu un dictum al programarii procedurale: "daca il folositi o data, scrieti codul. Daca il folositi si de doua ori, scrieti o procedura sau o functie." Este de asemenea consistent cu sfatul dat deseori tinerilor matematicieni: "Daca un concept sau teorie nu are cel putin trei exemple reale diferite, nu merita studiat".

O data ce candidatul pentru un obiect trece testul exemplelor multiple, el este plasat intr-un set de obiecte potentiale. Atributele obiectelor sunt acum testate cu ajutorul unei relatii "are-o", care poate sa ajute la formalizarea setului de atribute ale obiectului. Ar trebui sa scriem un set initial de functii membre pentru potentialul obiect, pe baza transformarilor rationale ale valorilor anumitor atribute ale obiectului propus.

Urmatoarea regula informala este verificarea a cat de potrivite sunt obiectele se refera la ierarhia clasei in care sunt proiectate clasele noi pe baza celor vechi. Aceasta relatie dintre clasa de baza si clasa derivata se descrie cel mai bine ca relatie "este-o". Daca afirmatia:

obiect 1 este un obiect 2

nu pare sa aiba sens (ignorand aspectul gramatical), atunci relatia nu este de forma

(clasa de baza, clasa derivata)

si, astfel, nu avem o relatie de mostenire.

Pe de alta parte, daca afirmatia pare sa aiba sens, atunci avem un candidat pentru o astfel de relatie. Numim aceasta "testul relatiei este-o". In acest caz, ar trebui sa desenam o diagrama a obiectului si oricaror relatii dintre obiect si alte obiecte.

Ar trebui sa enumeram functii membre potentiale si sa fim pregatiti sa gasim exemple de polimorfism. Aparitia polimorfismului sugereaza ca am ales corect relatia de mostenire. Daca nu exista polimorfism, atunci ar trebui sa avem indoieli in privinta descrierii corecte a functiilor membre, sau cel putin ca au fost insuficient de detaliat descrise.

Setul de obiecte potentiale si descrierile functiilor lor membre ar trebui rafinate la fiecare pas.

Exista si un test final al relatiilor care trebuie realizat pentru a incorpora obiectele intr-un design preliminar orientat pe obiecte al sistemului software. Preocuparea de data aceasta este daca obiectele enuntate formeaza un set complet de obiecte necesare pentru proiectarea sistemului software. Relatia pe care o cautam este "relatia foloseste-o".

Utilizam aceasta relatie prin intrebandu-ne daca afirmatia

obiect 1 foloseste obiect 2

are sens pentru perechile de obiecte considerate. Fiecare propozitie care are sens sugereaza fie o relatie client-server, fie o relatie bazata pe agent, si trebuie luata in considerare ca parte a proiectului programului. Daca nu putem gasi nici o propozitie de acest gen care sa aiba sens, atunci exista doua posibilitati: fie ca obiectele sunt insuficient specificate pentru a ne permite sa descriem intregul sistem, fie descrierea naturala a sistemului este un program procedural ce controleaza obiectele.

Remarcati ca obiectele pot fi inrudite cu multe alte obiecte. Mostenirea multipla este posibila, si de asemenea si obiecte multiple. Astfel, pasii anteriori ar trebui repetati pentru grupe de trei obiecte, patru obiecte, samd, pana cand proiectantii considera ca au fost descrise toate trasaturile orientate pe obiecte esentiale ale sistemului.

Rezumam pasii recomandati de determinare a obiectelor in Tabelul 2.

Tabelul 2

Metodologie de determinare a obiectelor

Alegeti un candidat pentru obiect.

Determinati un set de atribute si setul posibil de valori al acestora. Folositi relatia are-o. Enumerati toate transformarile obiectului.

Dezvoltati un set initial de transformari ale obiectului, pentru a servi ca functii membre. Lista atributelor si a valorilor lor ofera un set initial de transformari prin determinarea valorii fiecarui obiect, si atribuirii unei valori fiecarui obiect. Constructorul, destructorul si functiile de I/O trebuie de asemenea incluse.

Determinati daca exista mai multe exemple ale obiectului. Daca da, atunci plasati obiectul propus intr-un set de obiecte potentiale. Daca nu, scoateti-l, pentru ca a cazut testul exemplelor multiple.

Aplicati relatia este-o luand in considerare toate propozitiile de forma

obiect 1 este un obiect 2

Obiectele considerate pentru aceasta relatie ar trebui sa includa obiectul in dezvoltare si orice alte obiecte considerate ca fiind inrudite. (Biblioteca de clase poate fi consultata la acest pas al procesului). Fiecare afirmatie valida trebuie sa conduca la o relatie de mostenire. Fiecare relatie de mostenire trebuie ilustrata grafic.

Folositi polimorfismul si supraincarcarea operatorilor (si functiilor) pentru a verifica daca am descris obiectele suficient de detaliat. Verificati descrierea obiectului daca nu gasiti urme de polimorfism sau supraincarcare.

Folositi relatia foloseste-o

obiect 1 foloseste obiect 2

pentru a determina toate instantele relatiilor client-server sau bazat-pe-agent. Folositi aceste relatii pentru a determina aspecte ale proiectului programului.

Revizuiti obiectul, atributele si functiile membre ale acestuia, proprietatile de mostenire, polimorfismul, supraincarcarea, si relatiile sale cu alte obiecte, pentru a determina daca obiectul este complet in sensul ca nici o alta functie, atribute, sau relatii nu sunt necesare.

Repetati pasii 2-8 pentru toate combinatiile de obiecte relevante (triplete, cvadruple, s.a.m.d) pana cand rolul obiectului in orice sistem propus a fost descris adecvat.

Asigurati-va ca ati inteles pasii folositi in acest proces de determinare a obiectelor.

Importanta abstractizarii datelor si a ascunderii informatiei in cadrul obiectelor, trebuie sa va fie foarte clara. In plus, trebuie sa apreciati in oarecare masura puterea conceptelor de supraincarcare a operatorilor si mostenire. Vom considera de acum dezvoltarea de programe orientate pe obiecte mai mari.

In urmatoarele cateva sectiuni ale acestui capitol vom discuta aspecte ale proiectarii orientate pe obiecte si vom indica modul in care paradigma orientat-pe-obiecte pentru sisteme software difera fata de sistemele orientate pe proceduri. Vom indica de asemenea o metodologie a dezvoltarii sistemelor orientate pe obiecte pentru determinarea obiectelor fundamentale (si a metodelor corespunzatoare) ale acestora. Aceasta se va face in contextul dezvoltarii unei clase care descrie siruri de caractere.

Ne intoarcem acum la tema modelarii sistemelor orientate pe obiecte. Prima intrebare fundamentala pe care trebuie sa o punem este: care sunt obiectele sistemului?

O data ce am determinat aceste obiecte, trebuie sa raspundem la a doua intrebare fundamentala: care este setul de transformari care pot fi aplicate acestor obiecte?

Cateva definitii ar putea fi de folos. Despre un obiect abstract se spune ca avem atribute, care descriu o proprietate sau un aspect al obiectului abstract. Pentru orice instanta a unui obiect abstract, fiecare atribut poate avea valori.

Enumerarea atributelor este utila in evaluarea candidatului pentru un obiect. Atributele trebuie sa fie independente, in sensul ca o modificare a valorii unuia nu ar trebui sa afecteze valoarea altui atribut.

Exista inca o judecata care trebuie facuta pe baza listei atributelor: daca exista un singur atribut, atunci este posibil ca obiectul sa fie la un nivel jos de abstractizare. Acest lucru trebuie in general evitat, si astfel, vom dori sa avem cel putin doua atribute pentru fiecare obiect.

Vom ilustra aceste concepte prin cateva exemple in cadrul acestei sectiuni si a unora din cele ce urmeaza.

Consideram dezvoltarea tipica a unei clase pentru a descrie conceptul abstract al unui sir. Cateva atribute tipice a unui sir ar putea include lungimea, continutul, crearea sau distrugerea lui, afisarea acestuia. Toate acestea ne conduc la valori potentiale ale acestor atribute: lungimea poate fi 47, continutul poate fi "Imi place acest curs de inginerie a programarii" (nenumarand ghilimele), se poate afla in starea "creat" si poate fi afisat in fluxul standard de iesire cout. Valori alternative ale atributelor pot fi: lungimea de 81, continutul "Imi place acest curs de ingineria programarii si vreau sa fiu prezent cat mai des", si poate fi afisat intr-un fisier "fis_iesire".

Determinarea atributelor unui obiect si a setului de valori posibile pentru fiecare atribut sugereaza apoi functiile si tipurile de date necesare pentru implementarea metodelor folosite de aceasta clasa. De exemplu, trebuie sa avem o functie membru pentru clasa String care sa calculeze lungimea sirului de caractere. Aceasta lungime trebuie sa fie de tipul int (din moment ce acesta este tipul de date elementar predefinit in C). Trebuie sa avem un constructor care initializeaza continutul sirului si trebuie sa avem o functie pentru afisarea continutului in fluxul de iesire corespunzator.

Remarcati ce nu am determinat inca. Nu am mentionat deloc octetul null 0 folosit ca octet de incheiere pentru a indica finalul sirului; apoi, o alta intrebare ce se ridica este daca octetul de incheiere se ia sau nu in considerare la calcularea lungimii sirului, marind astfel, sau nu, lungimea acestuia.

Intr-adevar, nu exista nici o cerinta ca sirul sa fie implementat ca un set de octeti invecinati. Am putea alege sa urmam calea multor programe de editare text si folosi liste inlantuite pentru a lega matrici invecinate de caractere (si alte obiecte, precum grafice, in cazul procesorului de texte). Listele inlantuite sunt in special potrivite insertiei si stergerii textului in cadrul unui document de procesare de texte. Sunt posibile si alte forme de organizare a datelor.

Partea importanta ar fi sa remarcam ca nici una dintre deciziile privitoare la organizarea sau detaliile implementarii nu sunt relevante pentru obiectul string. Ce avem nevoie acum este o determinare a atributelor obiectului si a unui set de valori posibile pentru fiecare atribut. Cu o asemenea determinare, putem redacta prima tentativa de descriere a clasei. Astfel, prima incercare de definire a unui obiect string va avea probabil o definitie de genul clasei descrise mai jos. Nu ne punem problema sintaxei in acest moment:

class String

functii membre:

int lungime;

int strlen(String s);

void afisare(String s);

Se ridica aici cateva probleme, deoarece nu am determinat precis interfata. Constructorului trebuie sa ii specificam o marime pentru lungimea sirului. De asemenea, sunt si alte functii membre care trebuie sa aiba o interfata determinata. Astfel, va trebui sa facem o a doua iterare a proiectului clasei de reprezentare a sirurilor.

class String

functii membre:

int lungime;

String (char *arr); //terminat cu 0

int strlen();

operator <<;

Exista mai multe iterari care trebuie realizate pentru a avea o definitie completa a interfetelor acestei clase. Bineinteles, trebuie inca sa dezvoltam o implementare a metodelor. Omitem detaliile iterarii descrierii clasei in acest punct, din moment ce urmeaza sa le descriem in amanunt in Sectiunea 10, dupa ce am discutat cateva metodologii de dezvoltare a claselor. Implementarea codului pentru functiile membre ramane ca exercitiu.

8 Reprezentari ale proiectului orientat pe obiecte

In aceasta sectiune vom prezenta un model al unui obiect simplu pentru sistemul software al concentratorului de terminale descris in Sectiunea     Nu vom incerca sa imbunatatim modelul obiectului si il vom mentine la acelasi nivel inalt pe care l-am folosit pentru modelele anterioare, utilizand diferite reprezentari de proiect.

Reprezentarea este simpla (cel putin in acest moment). Vom folosi o casuta dreptunghiulara pentru a descrie un obiect, romburi si segmente de linie pentru a indica relatiile intre obiecte. Numele clasei este data deasupra unei linii orizontale, in interiorul casutei. Vom folosi conventia scrierii numelui clasei cu prima litera majuscula.

Relatia dintre obiecte primeste un nume in aceasta reprezentare. Relatia se numeste "este conectat la" si se comporta intr-o maniera similara relatiei "foloseste", pe care o discutam mai tarziu in acest capitol.

In casuta sunt incluse cateva atribute ale unui obiect arbitrar al clasei. Am fi inclus toate atributele, dar ele erau prea multe.

In partea de jos a diagramei, enumeram din nou clasele care sunt in partea de sus a diagramei, din nou folosind o reprezentare grafica. Clasele in aceasta lista au valori specifice pentru fiecare atribut al vreunui obiect al acestora.

Remarcati ca acest model nu mentioneaza structura de date coada care va fi probabil folosita pentru a pastra informatia care circula intre concentrator si terminal.

Putem avea doua viziuni diferite ale sistemului orientat pe obiecte: modelul obiect sau modelul interfata. Vom discuta pe rand aceste doua viziuni.

In reprezentarea modelului obiect, vom folosi o notatie extinsa entitate-relatie (E-R). Vom folosi conventia ca numele unei clase va fi dat cu litere mari si instantele ei, cu litere mici.

Punctul de start al discutiei noastre il constituie diagramele date in sectiunea     Astfel de diagrame pot oferi o viziune buna de nivel inalt al sistemului.

Diagramele obiect pot fi in continuare imbunatatite prin incorporarea in diagrama a cardinalitatii fiecarei relatii. Figura 10 ilustreaza acest lucru. Numerele de langa sau de deasupra unei relatii indica numerele de elemente de pe fiecare parte ce au acea relatie. Cardinalitatea poate fi una dintre urmatoarele: o valoare precisa, un rang de valori, simbolul '*' denotand 0 sau mai mare, ori simbolul '+' denotand 1 sau mai mare. In figura 10 am folosit '+' si rangul.

Un model obiect ar trebui extins pana cand acesta descrie abstractizarile esentiale ale obiectelor din sistem. Din pacate, dupa cum am indicat pana acum modelul obiect in aceasta sectiune, este inadecvat pentru a descrie complet relatia dintre diferite obiecte. Avand in vedere aceasta limitare, vom incerca sa incorporam in modelul nostru interfete intre diferite obiecte.

O metoda este de a folosi tabelele de stare. Termenii "diagrama de stare", "masina de stare" si "masina de stari finite" sunt deseori folosite ca sinonime ale "tabelei de stare". Aceasta este una dintre cele mai vechi metode de descriere a sistemelor. Poate fi cu siguranta datata inaintea eforturilor curente ale design-ului orientat pe obiecte.

O tabela de stare pentru concentratorul de terminale ar putea avea sase stari, pe care le numim ITP, ICP, ICPUP, ECPUP, ECP si ETP. Acronimele provin de la: Intrare Terminal Pregatita, Intrare Concentrator Pregatita, Intrare CPU Pregatita, Iesire CPU Pregatita, Iesire Concentrator Pregatita, si respectiv Iesire Terminal Pregatita.


Figura 10. Adaugarea informatiei de cardinalitate la o notatie cu model obiect. Sursa: Leach, Proiectare si Programare C++ Orientate pe Obiecte, Academic Press, 1995

Ilustram starile sistemului concentrator de terminale in Figura 11. Notatia este usor diferita de cea uzuala in care nu am specificat starea initiala in care sosesc intrarile sistemului (de la tastatura) si starea finala in care iesirile ies definitiv din sistem (ele fiind afisate pe terminalul ecran).

Este bine de stiut cum sa folosim reprezentarile existente ale sistemelor atunci cand incercam sa le descriem in termeni orientati pe obiecte. Avem deseori un model obiect al unui sistem. Sugestiile noastre pentru utilizarea modelelor informationale existente si a diagramelor in modelarea cu obiecte pot fi sumarizate precum urmeaza:

Daca exista o diagrama a unui model informational, folositi-o pentru a determina relatiile initiale, in special cele de agregare.

Examinati listele de atribute cautand indicatii ale structurilor de date si a unui set preliminar de transformari pentru a opera asupra valorilor acestor atribute.

Daca nu exista nici un model informational disponibil, treceti direct la o descriere a obiectelor din sistem.


Figura 11. O diagrama de stare pentru sistemul concentratorului de terminale. Sursa: Leach, Proiectare si Programare C++ Orientate pe Obiecte, Academic Press, 1995

9 Principii ale proiectarii software pentru programe orientate pe obiecte

Toate metodele de reprezentare a design-ului discutate anterior au fost create pentru a imbunatati calitatea proiectelor software si eficienta proceselor utilizate pentru a le crea. Tehnicile de reprezentare a design-ului pentru sisteme traditionale, organizate procedural, sunt mult mai uzuale decat cele pentru sisteme orientate pe obiecte. Acest lucru nu este surprinzator, data fiind relativa noutate a tehnicilor orientate pe obiecte.

Asa cum am vazut in sectiunea anterioara, descompunerea a fost tehnica majora folosita pentru dezvoltarea de software procedural o data ce am determinat schemele software de nivel inalt, daca ele exista, care au descris sistemul ce trebuie proiectat. Exemplul construit anterior folosind unealta CASE MacTAGS a accentuat abordarea bazata pe descompunere.

Instalarea completa a sistemului TAGS pe statii de lucru puternice includ de asemenea o facilitate de generare automata de cod. Disponibilitatea extensiilor uneltelor CASE care ofera generatoare automate de cod nu este restrictionata la acele unelte CASE care suporta proiecte orientate pe proceduri. Remarcam ca anumite trasaturi inrudite pot fi gasite in diverse pachete software folosite in dezvoltarea orientata pe obiecte. De exemplu, versiunea 5.0 si mai mare a Sistemului de Dezvoltare Borland C++ includ facilitatea generarii de cadre (framework) de cod cu fisiere antet si descrieri de clase din modelele grafice ale obiectelor care alcatuiesc un sistem. Sistemul ROSE al Rational Corporation este un alt exemplu de sistem popular care suporta analiza orientata pe obiecte cu cadre de cod.

Totusi, proiectarea orientata pe obiecte se concentreaza pe dezvoltarea de clase complete pentru a descrie obiecte. Ideea este ca toate metodele sau functiile membre necesare vor fi livrate in descrierea clasei. Astfel, preocuparea principala este proiectarii clasei spre a fi completa, astfel ca posibilele interactiuni sa fie tratate prin interfete corespunzatoare. Obiectele interactioneaza apoi prin trimitere de mesaje de la o clasa la alta si clasele individuale reactioneaza doar la mesajele pe care le primesc. Obiectele sunt vazute ca autonome, fara alte interactiuni decat cele specificate in interfata obiectului.

Utilizarea claselor abstracte poate fi in special folositoare daca cerintele software-ului nu sunt complet identificate inainte de a incepe proiectarea, asa cum este cu siguranta cazul procesului de dezvoltare software condus de piata si programat concurent, atat de uzual in lumea computerelor personale.

In aceasta abordare, interfetele unui obiect al sistemului sunt specificate devreme. Detaliile de implementare ale metodelor pot fi dezvoltate ulterior. Daca sunt necesare functionalitati noi, acestea se ofera in metode asociate cu un obiect, nu in interfata obiectului. O functie virtuala pura (una care nu are detalii de implementare si este folosita drept clasa de baza cu interfete ce pot fi folosite de clasele care o mostenesc) este deseori folosita in acest scop in C++.

Chiar si in cazul cel mai defavorabil, dezvoltarea functiilor membre ale unei functii poate sa se desfasoare concurent cu proiectarea obiectului. Daca se adauga o interactiune noua la interfata unui obiect, majoritatea metodelor existente nu trebuie modificate. Trebuie adaugate doar metode noi pentru a implementa interfata aditionala.

In continuare dam o ilustrare a efectelor diferitelor abordari de proiectare a sistemelor orientate pe obiecte. Consideram situatia simpla de descriere a clasei ce reprezinta patrulatere (obiecte geometrice cu patru laturi). Dorim sa dezvoltam o structura de clasa pentru descrierea de patrulatere, cu dreptunghiuri si patrate drept tipuri speciale de forme geometrice.

Avem mai multe optiuni la dispozitie. Putem crea o ierarhie cu o clasa primitiva numita varf. Putem construi o clasa numita latura, ce foloseste clasa varf, si folosi apoi clasa latura pentru a construi o noua clasa numita figura. Clasa figura poate fi folosita pentru a construi patrulatere ca un subset.

Aceasta constructie este ilustrata in Figura 12. Prezentam secvente de cod sursa pentru implementarea acestei organizari in Exemplul 3.


Figura 12. O ilustrare a organizarii proiectarii unor figuri geometrice pe baza primitivei varf

Din pacate, nu exista o modalitate clara de capturare a notiunii unei figuri geometrice ca fiind patrat sau dreptunghi. Am putea modifica clasa data in fisierul figura.cpp, dar aceasta pare un procedeu ciudat. Un alt design potential foloseste o ierarhie de obiecte bazate pe o relatie este-o, din moment ce un patrat este un dreptunghi si un dreptunghi este un patrulater. Invitam cursantul sa examineze orice clasa de biblioteca standard care are obiecte grafice pentru a vedea ca nici una din aceste abordari nu este folosita in practica. In loc de aceasta, ierarhia este deseori inversata, iar un dreptunghi mosteneste de la un patrat. Remarcam ca flexibilitatea paradigmei orientate pe obiecte ne permite sa alegem dintre aceste alternative de proiectare.

// Fisier: varf.cpp

class Varf

// Fisier: latura.cpp

#include 'varf.cpp'

class Latura : public Varf

// Fisier: figura.cpp

#include 'latura.cpp'

class Figura : public Latura

Exemplul 3. Secvente de cod sursa C++ pentru organizarea figurilor pe baza primitivei varf

Exista un dezavantaj al inlesnirii acestei flexibilitati a cerintelor concurente, proiectarii si codificarii. Orice metoda adaugata la o clasa in ultimul moment inainte de lansare va avea parte de testari minimale datorita crizei de timp. Este foarte putin probabil ca un obiect sa fie testat pentru toate tipurile posibile de raspuns, in special daca interfetele sunt polimorfice sau daca unii operatori sunt supraincarcati. Astfel, un utilizator al software-ului poate observa multe greseli de functionare, mai ales daca utilizatorul opereaza software-ul in moduri neprevazute de proiectanti.

In multe organizatii de dezvoltare software, tratarea unor asemenea probleme potentiale este amanata pentru urmatoarea lansare. Astfel, testarea corectiva a componentelor software a unei versiuni lansate anterior poate sa apara in timpul dezvoltarii (cerinte, proiectare, codificare, testare) a urmatoarei lansari. Determinarea momentul de lansare a sofware-ului, de comandare a testarilor aditionale, si determinarea trasaturilor ce vor fi incorporate in lansari noi sunt in mod clar esentiale pentru a avea succes in mediul software condus de piata. Ne vom intoarce la acest aspect in Capitolul 6 cand vom studia testarea, si din nou in Capitolul 8 cand vom studia managementul configurarii.

Modelele prezentate in acest capitol sunt intentionate exclusiv ilustrarii. Orice model realist al unui sistem complet ar fi mult mai detaliat decat ceea ce vom prezenta in urmatoarele sectiuni. Modelele date aici descriu sistemul doar la nivelul cel mai inalt al sau. Dupa ce ati parcurs acest capitol, ar trebui sa puteti aprecia puterea expresiva a catorva reprezentari diferite ale proiectului pentru sisteme software procedurale si orientate pe obiecte.

10 Aspecte ale proiectarii claselor

Este necesar sa discutam despre anumite dificultati asociate cu dezvoltarea de programe care folosesc metodele de definire a claselor descrise in sectiunea anterioara. Metodologia descrisa in sectiunea anterioara presupune ca sistemul software a fost dezvoltat intr-un vacuum. Adica, am descris cateva atribute pe care le consideram asociate cu un anumit tip de obiect si am descris cateva interfete potential folositoare intre aceste obiecte si altele (precum matrici de caractere si siruri I/O). Nu am acordat atentie claselor dezvoltate anterior, ce ar putea fi inrudite cu clasa noastra si ar incuraja utilizarea unor interfete similare.

Daca exista un set de clase inrudite cu standarde similare pentru interfetele lor, atunci trebuie macar sa luam in considerare aceste interfete inainte de a fixa interfetele ce fac parte din descrierea concurenta a obiectelor.

Acest aspect nu poate fi suficient de accentuat. Dezvoltarea unui obiect trebuie sa aiba loc de-a lungul liniilor ce ii definesc atributele si valorile tipice ale acestor atribute. Aceasta poate fi realizata prin metoda uzuala de rafinare pas cu pas, atat de familiara inginerilor software. Dezvoltarea unui obiect util (unul care poate fi folosit intr-o varietate de situatii importante) necesita ca interfetele catre obiectele existente sa fie luate in considerare in stadiul de dezvoltare. Altfel, obiectele pe care le dezvoltam vor avea o utilitate puternic limitata.

Ilustram acest lucru prin urmatoarea analogie: sa consideram stadiul curent al dezvoltarii hardware-ului unui computer. Daca un proiectant hardware proiecteaza un supercomputer de inalta performanta, special dedicat unei sarcini sau un microprocesor special pentru controlul sistemelor incorporate, el va folosi componentele dezvoltate anterior si care au interfete bine-definite si bine-documentate. Aceste componente hardware bine-proiectate au nivele predictibile de performanta in ceea ce priveste viteza de tact, rata de transfer a datelor, reactia la anumite intreruperi, utilizarea puterii etc. O piesa hardware noua care nu adera bine la aceste interfete standard este putin probabil sa fie folositoare in afara unei arii limitate de aplicatii. Doar un design revolutionar cu aplicabilitate sau performante iesite din comun prezinta posibilitatea de a fi folositoare; o interfata neobisnuita cu aplicatii comune sau performante medii nu poate avea mare succes.

Exact aceeasi situatie se aplica la dezvoltarea claselor care pot fi folosite drept componente software reutilizabile. Dezvoltarea unei clase nu poate fi facuta intr-un vacuum. Trebuie sa tina cont de alte clase ale bibliotecii de clase, pentru a face uz in mod eficient de aceste clase dezvoltate anterior. Catalogul de biblioteca si orice unelte software de examinare a diferitelor biblioteci sunt extrem de importante la dezvoltarea claselor ce interactioneaza cu sisteme reale.

Remarcati ca trebuie sa mai facem inca un lucru pentru a ne asigura ca clasele pe care le dezvoltam fac uz eficient de resurse, in special de timpul programatorului. Daca exista o relatie intre clasa noastra si una sau mai multe clase deja existente, este posibil sa putem folosi functiile dezvoltate anterior, ce au fost membre ale vreunei clase deja existente. Acest lucru se realizeaza usor daca putem folosi mostenirea.

Putem de asemenea folosi functii asociate cu un obiect, daca functiile au fost declarate original ca functii friend. (amintiti-va ca functiile friend sunt permise in C++, dar nu in limbaje orientate pe obiecte precum Java.) Chiar daca functiile nu au fost declarate original ca fiind friend, s-ar putea sa avem posibilitatea sa modificam definitia clasei deja existente pentru a face functiile necesare functii membre si recompila sistemul.

In orice caz, un proces de proiectare software eficient necesita o verificare a resurselor software disponibile.

Grady Booch este unul dintre cei mai recunoscuti experti ai comunitatii de programare orientata pe obiecte. El a remarcat ca in majoritatea programelor orientate pe obiecte, de calitate inalta, multe obiecte esentiale sunt grupate in cateva clase inrudite, mai degraba decat grupate doar prin mostenire. El afirma ca singurele programe care au toate obiectele inrudite sunt cele relativ triviale.

In mod clar, determinarea claselor disponibile in bibliotecile de clase este doar un punct de start in dezvoltarea de programe orientate pe obiecte. Totusi, acest lucru reprezinta un pas esential in proiectarea unui sistem orientat pe obiecte.

11 Un exemplu de dezvoltare de clasa - Clasa String

In aceasta sectiune ne vom intoarce la discutia privind clasa String pe care am inceput-o in Sectiunea 7. Vom aplica asupra acestei clase regulile enumerate in Tabelul 2 pentru a obtine ceea ce speram sa fie o abstractizare satisfacatoare a propietatilor pe care le dorim intr-o clasa String abstracta. Clasa String prezentata in acest capitol a fost originar dezvoltata de Eric Charles pentru un proiect condus de Bernard Woolfolk la Universitatea Howard.

Initial, am remarcat ca aceasta clasa avea doua functii membre: un constructor String() si o functie strlen() pentru a calcula lungimea unui obiect al clasei. Suntem la primul pas al procesului descris in Tabelul 2: am selectat un candidat pentru un obiect.

Pasul doi al procesului necesita enumerarea atributelor acestui obiect. Lista de atribute indicata anterior a fost:

lungime

Nu exista o mentiune explicita in cadrul discutiei anterioare, privitor la datele pe care dorim sa le stocam in String. Ne-am asteptat cu siguranta sa folosim datele in functia strlen(). Reparam aceasta omitere incluzand datele acum. Urmatoarea lista a atributelor pentru un obiect String este:

lungime

date din String

Aceste atribute au sens ca atribute potentiale ale obiectelor String, datorita faptului ca ambele afirmatii:

Un String are o lungime.

si

Un String contine date.

au sens. A doua propozitie ar putea fi probabil parafrazata ca:

Un String are continut.

si, astfel, vom folosi termenul continut in locul termenului date din lista initiala de atribute.

Pentru a ne asigura ca acestea sunt atribute rezonabile, vom enumera cateva valori specifice intr-un tabel:

Atribut

Valoare specifica

lungime

continut

Frecventati cursul

In pasul trei, consideram transformari posibile ale obiectului. Functii membre relevante pot fi:

Constructor

Destructor

Initializarea unui sir

Atribuirea de continut unui alt sir (constructor de copiere)

Date de intrare ale unui sir

Date de iesire ale unui sir

Este esential sa incepem sa luam in considerare modul in care interfetele acestor functii membre trebuie sa arate. Constructorul implicit C++ si functiile destructor nu primesc argumente si nu returneaza valori. Daca dorim sa initializam un obiect String, o vom specifica aici. Este posibil sa dorim sa avem un constructor de forma

String(char * init);

sau poate

String(const char * init);

Aici, init reprezinta o matrice de caractere terminata cu null.

Functiile membre de I/E vor supraincarca cu siguranta operatorii << si >>. Probabil ca ar fi de folos sa permitem scrierea sirurilor in alte fluxuri decat cin, cout si cerr, pentru ca functiile noastre de I/E sa fie din nou supraincarcate.

Remarcati ca nu ne-am legat de aspecte precum includerea (numararea) sau nu a octetului null in lungimea obiectului. Acestea sunt detalii relevante fie pentru interfete catre alte obiecte sau specificari ale implementarii.

Sunt multe exemple de siruri, deci obiectul String propus de noi trece cu siguranta testul "exemplelor multiple".

Vom aplica acum pasul cinci al procesului pentru a determina daca exista relatii de mostenire. Pentru a face acest lucru, trebuie sa determinam un set de obiecte pe care le consideram ca avand relatii de mostenire cu noul obiect propus de noi. Cu posibilele exceptii ale listelor si matricilor, nu exista obiecte probabile in acest moment, deci vom trece la pasul sase al procesului. Daca am considerat ca exista o relatie puternica este-o intre clasa String si o clasa matrice (abstracta), atunci am avea relatii de mostenire intre aceste clase. O afirmatie similara avem pentru clasa String in relatie cu o clasa (abstracta) pentru liste inlantuite.

In exemplul 4, ilustram starea clasei noastre String dupa ce am folosit pasii 1-5 ai procesului, asa cum au fost enuntati in Tabelul 2. Fisierul antet String.h include definitiile de baza necesare pentru clasa String descrisa pana acum.

// tentativa initiala de definire a clasei

// String, folosind pasii 1-5 ai

// procesului de dezvoltare de obiect.

class String

Exemplul     O clasa String definita de utilizator - prima iterare a pasilor 1-5 din procesul de dezvoltare a clasei

Asa cum vom vedea, codul din Exemplul 4 nu este foarte complet, ca descriere a clasei String. Vom continua acum procesul de dezvoltare a clasei.

In pasul sase al procesului, ne intrebam daca exista polimorfism sau supraincarcare. Daca nu, probabil ca nu am descris toate transformarile (functii membre) ale obiectului. In acest caz, avem supraincarcarea (cel putin) a unui constructor si a functiilor I/E, astfel ca este probabil ca am facut cel putin o anumita utilizare a trasaturilor orientate pe obiecte ale clasei.

In pasul sapte, ne intrebam daca exista o instanta a relatiei foloseste-o intre obiectul nostru si alte obiecte. Aici, cautam relatii client-server sau bazat pe agent. Datorita simplicitatii obiectului nostru String, o astfel de relatie este improbabila, deci trecem la pasul opt.

Pasul opt al procesului implica revizuirea starii curente a dezvoltarii clasei si verificarea lipsei vreunor relatii sau transformari. Acesta este un moment ideal pentru o parcurgere structurata a obiectului, preferabil fiind insa ca parcurgerea si revizuirea sa fie realizate de altcineva, si nu de catre proiectant. Scopul revizuirii este de a verifica inconsistentele proiectului, cautand relatii lipsa sau prost aplicate, dar si complicatii inutile.

In exemplul nostru, am oferit foarte putine functii dintre cele disponibile in colectia standard de functii C pentru manipularea sirurilor. Cateva functii tipice accesate in fisierul antet string.h al limbajul standard C sunt strcmp(), strcat() si strcpy(). Ar fi potrivit sa adaugam acum cat mai multe dintre acestea in clasa noastra String.

Pasul noua ne permite sa extindem relatia este-o catre mai multe clase o data, adaugand astfel posibilitatea mostenirii multiple descrierii clasei noastre. Vor apare acum instante mai complexe ale relatiei foloseste-o.

In majoritatea proiectelor (design-urilor) incepatoare este probabil indicat sa repetam pasii 2-8 doar pana la triplete de clase, atata timp cat nu ne asteptam sa apara o relatie mai complexa.

Dupa ce am finalizat acest proces, vom fi obtinut o descriere a datelor interne si interfetelor obiectului String. Singurele lucruri pe care trebuie sa le facem pentru a crea cu adevarat o asemenea clasa sunt de a prezenta definitia datelor si functiilor membre intr-o forma corecta sintactic, si sa codificam detaliile functiilor membre.

Prezentam o descriere mai completa a clasei String in exemplul 5. Remarcati ca avem cu mult mai multe functii membre decat anterior. Unele dintre functiile membre noi sunt incluse pentru ca dorim sa avem interfete catre alte obiecte de tipul String, nu doar date de tipul char*.

Am inclus posibilitatea de modificare a valorilor argumentelor prin utilizarea operatorului & in diverse locuri in cadrul declaratiilor functiilor membre. Declaratiile sunt de tipul const, precum in signatura argumentului

const String& string;

pentru ca dorim sa evitam fenomenul de depasire la copierea intregului continut al obiectului String, dar si sa pastram nemodificata valoarea argumentului. Reamintiti-va ca aceasta se numeste transmiterea de parametri prin referinta constanta.

Ar trebui de asemenea sa remarcati domeniul larg de operatori din exemplul 5, pentru actiuni precum comparatii lexicale. Multi dintre acesti operatori sunt supraincarcati.

Am inclus de asemenea in exemplul 5 un operator friend pentru interactiunea cu clasa ostream:

friend ostream& operator << (ostream& s, String &str);

// contine definitia clasei String, folosind cei noua

// pasi ai procesului de dezvoltare a obiectului

class String

Exemplul 5. O clasa versiune mai completa a clasei String

Exista multe moduri de a descrie un obiect abstract reprezentat de clasa String. Ar trebui sa comparati descrierile celor doua clase date pana acum in aceasta sectiune cu clasa String echivalenta oferita de compilatorul Dvs. C++. Ar trebui de asemenea sa consultati biblioteca standard C++ atunci cand va deveni disponibila, sau cartea lui Plauger despre standardul ANSI pentru o biblioteca C++.

Sunt necesari pasi aditionali daca scopul este cel de a dezvolta clase care incurajeaza folosirea reutilizarii componentelor software. Sugestiile lui Johnson si Foote sunt metode tipice de dezvoltare a claselor reutilizabile de obiecte. Scopul este de a crea clase care nu reprezinta doar abstractizari ale datelor, ci care sunt si usor de testat. Sugestiile lor sunt prezentate in Tabelul 3.

Tabelul 3

Cateva metode de incurajare a claselor reutilizabile

Introducerea recursivitatii in clase pentru a ajuta abstractizarea.

Eliminarea analize de caz in dezvoltarea functiilor membre.

Reducerea numarului de argumente.

Reducerea marimii metodelor.

Ierarhiile claselor ar trebui sa fie adanci si inguste.

Varful ierarhie trebuie sa fie abstract.

Minimizarea accesului la variabile.

Subclasele trebuie sa fie specializari ale claselor mai mari.

Divizarea claselor mari in mai multe clase mai mici.

Factorizarea deosebirilor de implementare.

Separarea metodelor care nu comunica.

Trimiterea de mesaje catre componente, in locul trimiterii catre obiectul in sine.

Reducerea transmiterii parametrilor.

Aceste reguli sunt folositoare atunci cand proiectam sisteme mari cu clase complexe. Ele sunt probabil mult prea stufoase pentru exemplele simple prezentate in acest capitol.

Vom prezenta acum descrierea finala a clasei noastre String. Ea este ilustrata in Exemplul 6. Trasaturile noi includ un set de functii non-membre (libere) pentru realizarea altor actiuni. Asa ca si anterior, ar trebui sa comparati aceasta clasa cu clasa String disponibila sistemului Dvs.

Descrierea clasei este completa si ilustreaza efectele diferitelor iterari ale procesului de dezvoltare a obiectului. Metodele (functiile membre) sunt mici, fiecare realizand actiuni specifice asupra tipurilor selectate de operatori.

Exista multe instante de operatori supraincarcati precum <= si >=, pentru a avea programe simple de comparare si concatenare a sirurilor. Ar trebui sa remarcati utilizarea cuvenita a pointerilor constanti din cadrul functiilor membre ce implementeaza aceste operatii de concatenare cu siruri noi si siruri existente.

Observati de asemenea prezenta unor functii libere pentru realizarea comparatiilor si concatenarilor. Aceste functii libere sunt folosite atunci cand primul argument este o matrice de caractere terminate cu caracterul null, mai degraba decat un obiect al clasei String. Aceasta este o indicatie a faptului ca avem acum o clasa String completa.

// contine definitia clasei String, si functii operator

// supraincarcate non-membre

class String

//friend pentru operatorul supraincarcat de I/E

//al clasei ostream

friend ostream& operator << (ostream& s, String &str);

private:

char * d_string_p; //pointer la caracter

//operatori non-membri (liberi)

String operator + (const char* str, const String& string);

int operator == (const char* str, const String& string);

int operator != (const char* str, const String& string);

int operator > (const char* str, const String& string);

int operator >= (const char* str, const String& string);

int operator < (const char* str, const String& string);

int operator <= (const char* str, const String& string);

Exemplul 6. Tentativa finala de realizare a clasei String definite de utilizator

Bineinteles, am avea nevoie de implementari pentru fiecare dintre functiile membre ale acestei clase. Din motive de spatiu nu am inclus codul sursa in acest curs. Marea parte a detaliilor de implementare a metodelor este clara. Ar trebui sa comparati proiectul clasei noastre cu cel al clasei echivalente din biblioteca standard de clase ANSI. Ar trebui sa remarcati utilizarea puternica a transmiterii argumentelor prin referinta, folosind simbolul & dupa numele argumentului.

Exista multe functii membre pentru ca exista multe oportunitati de supraincarcare a operatorilor. Aceasta conduce la un numar mare de cazuri potentiale de test. Vom discuta testarea programelor orientate pe obiecte in Capitolul 6.

12 Interfata cu utilizatorul

Succesul de piata al multor produse software depind mult mai mult de interfata cu utilizatorul a software-ului sau setul de trasaturi vizibile decat de cele trasaturi ascunse precum robustetea. Aceasta este in special adevarata in pietele "aglomerate" precum cea a aplicatiilor software pentru computere personale, in care sunt multe produse concurentiale.

In aceasta sectiune, vom prezenta sumar acest punct de vedere. Intentia este de a va convinge ca exista mai multe aspecte ale interfetei cu utilizatorul decat folosirea mai multor culori, de mesaje clipitoare, icoane inteligente, sunete sau animatii.

Exista atat o arta, cat si o stiinta a proiectarii interfetei cu utilizatorul. Majoritatea sistemelor software curente au interfete cu utilizatorul bazate pe paradigma WIMP sau Fereastra, Interactiune, Mouse, Pointer (Window, Interaction, Mouse, Pointer). Sistemul de operare Macintosh si variantele Microsoft Windows (Windows 97, Windows 95, Windows, Windows NT si Windows for Workgroups) urmaresc aceasta paradigma.

Interfata grafica cu utilizatorul a pachetelor software de calitate inalta si paginilor web au o consistenta care este reflectata in simplitatea proiectarii meniului. De exemplu, majoritatea interfetelor grafice cu utilizatorul ale software-urilor pentru computere personale au meniuri pull-down cu operatiile pe fisiere in partea de sus, stanga a ecranului.

Vom face acum distinctia intre un meniu pull-down si un meniu pop-up. Un meniu "pull-down" este unul in care utilizatorul selecteaza o optiune dintr-un set de optiuni prin deplasarea unui dispozitiv de indicare precum mouse-ul la o pozitie fixa si selectarea acelei pozitii prin apasarea unui buton de mouse sau a altor dispozitive de selectare. Aceasta secventa de operatii determina aparitia unui meniu din partea de dedesubt a locului in care a fost plasat dispozitivul indicator (mouse-ul). Utilizatorul muta apoi indicatorul in josul listei de optiuni ale meniului pana la selectarea uneia dintre acestea. (Utilizatorul are optiunea de terminare a procesului prin eliberarea butonului mouse-ului sau deplasarea mouse-ului pe o alta pozitie). Setul initial de optiuni listate intr-un meniu pull-down sunt intotdeauna disponibile utilizatorului.

In contrast cu informatia dintr-un meniu pull-down, nici o informatie din cadrul unui meniu "pop-up" nu ii este vizibila utilizatorului atata timp cat el nu intreprinde o actiune specifica, precum apasarea unui buton de mouse sau a combinatiei de taste echivalente.

Actiunea unui meniu pull-down tipic inainte si dupa apasarea butonului de mouse este ilustrata in Figurile 13 si 1 Comparati aceste meniuri cu Figurile 15 si 16, care ilustreaza actiunea meniurilor pop-up.

Remarcati ca meniurile pull-down apar in partea de sus a ecranului ilustrat in Figura 13, atata timp cat ruleaza aceasta aplicatie (Microsoft Word) si fereastra este afisata pe ecran. Comparati aceasta cu Figura 14 in care acelasi meniu pull-down este ilustrat impreuna cu un meniu nou obtinut din selectia unei optiuni din acest meniu.

Figura 13. Exemplu de meniu pull-down inainte de a face selectia

Figura 1 Exemplu de meniu pull-down dupa ce selectia a fost realizata

Figura 15. Exemplu de meniu pop-up inainte de a face selectia

Figura 16. Exemplu de meniu pop-up dupa ce selectia a fost realizata

O gama mare de optiuni determinate de disponibilitatea meniurilor pull-down si pop-up produce probleme mari pentru un proiectant de interfete. El trebuie sa fie atent sa nu foloseasca aceste trasaturi tentante doar pentru ca ele sunt disponibile. Urmatoarele reguli de baza va pot fi folositoare:

Folositi un meniu pull-down atunci cand optiunile trebuie sa fie intotdeauna vizibile

Folositi un meniu pull-down pentru a furniza un set de optiuni pentru un utilizator incepator

Folositi un meniu pop-up atunci cand optiunile nu trebuie sa fie intotdeauna vizibile

Folositi un meniu pop-up pentru a-i oferi shortcut-uri unui utilizator avansat

Regulile de baza au trebuit sa fie incomplete datorita lipsei de spatiu si datorita gamei largi de aplicatii si utilizatori potentiali. Nu in ultimul rand, ele ilustreaza cateva probleme majore pentru un proiectant de interfete: necesitand o abordare consistenta pentru proiectul interfetei, in timp ce ofera simultan prescurtari pentru a-l ajuta pe utilizatorul experimentat sa fie mai productiv.

Remarcam ca in multe situatii, o interfata grafica cu utilizatorul nu este potrivita. Sa luam in considerare cazul unui coleg de la Universitatea Howard, care colaboreaza cu colegi din cercetarea stabilitatii software din toata lumea. El a dezvoltat impreuna cu asistentul sau un set de unelte pentru analiza fisierelor de date pentru a evalua rata de crestere a stabilitatii sistemelor software. Fisierele de date contin momentele in care defectele software au aparut in timpul procesului de testare.

Datorita faptului ca multe sisteme luate in considerare de el nu sunt conectate la Internet din motive de securitate, el trebuie deseori sa isi realizeze munca de cercetare fara acces la statii de lucru si servere disponibile in mediul lui de acasa, din Universitatea Howard. Astfel, a dezvoltat o versiune mai mica pentru setul sau de unelte software pentru un computer personal. Setul de unelte software trebuie sa functioneze in toate mediile, si astfel, interfata grafica cu utilizatorul corespunzatoare mediului Windows 95, sau orice alta versiune Microsoft Windows nu a putut fi folosita.

In schimb, software-ul functioneaza perfect intr-un mediu MS-DOS. Interfata cea mai simpla este cea mai buna in acest caz.

Un alt exemplu pentru o interfata utilizator non-grafica si condusa de meniuri pentru un sistem folosit pentru selectarea unei serii de fisiere ce trebuie analizate de un sistem software. A fost dezvoltat un sistem cu terminale bazate pe caractere si s-a investit efort considerabil in dezvoltarea de fisiere text care au fost tiparite pentru a simula terminale grafice de ecran. Mai multe meniuri, comprimate pentru a face economie de spatiu, sunt ilustrate in Figura 17 pana la 22.

1989 B&S Enterprises, Inc.

 


Figura 17. Un exemplu de ecran de deschidere al unui sistem bazat pe text si condus de meniuri

. Coupling Measures

2. Coupling Description

3. Help

4. Exit

 


Figura 18. Un exemplu de meniu principal al unui sistem bazat pe text si condus de evenimente

. Main Menu

2. Coupling Description

3. Help

4. Exit

 


Figura 19. Un exemplu de meniu secundar dintr-un sistem bazat pe text si condus de evenimente

You may have output sent to a file

or to the screen.

The default output file is

"Coupling.out."

The default option is the screen.

1 = Screen

2 = File

 


Figura 20. Un exemplu de meniu de optiuni de iesire dintr-un sistem bazat pe text si condus de evenimente

The system for Analyzing Ada Coupling (SANAC) measures the level of interconnections (coupling) between Ada modules contained in user-specified Ada source files. The code must be syntactically correct for accurate results.

Select options from the Main Menu:

Perform Coupling Analysis on the Ada Source files you specify.

Get a Description of Coupling types.

Get Help (* Presently Invoked*)

Exit from SANAC.

 


Figura 21. Un exemplu de ecran help dintr-un sistem bazat pe text si condus de evenimente

1989 B&S Enterprises, Inc.

RELEASE 2.0

 


Figura 22. Un exemplu de ecran de inchidere dintr-un sistem bazat pe text si condus de evenimente

Imaginati-va acum ca versiunea executabila a software-ului se numeste "sanac". (asa cum o sugereaza ecranul de deschidere, software-ul a fost numit sanac pentru a reflecta ca s-a intentionat ca un sistem sa analizeze cuplarea software-ului scris in limbajul de programare Ada.) Prin setarea unui simplu argument al liniei de comanda cum ar fi in C sau C++, putem reduce cele sase selectii de meniu din Figura 17 - 22    la o singura linie de comanda

sanac file.a

care este cu mult mai simpla si are cu mult mai putine apasari de taste ca si sistemul condus de meniuri. Simplitatea este apreciata cel mai mult de un utilizator experimentat.

Elementele de meniu pot fi grupate in mai multe moduri; cea mai uzuala organizare este prin functionalitate sau alfabetic. Este preferabil in general sa ordonam diferite optiuni dupa probabilitatea cu care vor fi folosite. Este in general stabilit prin acord comun ca optiunea de iesire este plasata ultima printre optiunile disponibile, in orice meniu in care apare.

Binenteles, cea mai grava greseala posibila in proiectarea interfetei utilizator este de a ne astepta ca utilizatorul sa ofere date de intrare fara a avea un prompt sau o descriere a datelor de intrare. Ce faceti ca raspuns la un prompt al interfetei utilizator, precum cel din Figura 23?

 


Figura 23. Cel mai clar exemplu de interfata utilizator proasta?

Exista o nota finala despre interfetele utilizator. Folositi o unealta de verificare a sintacticii in toate fisierele text, ecranele de meniu sau optiuni de meniu. Urmati-le pe acestea de o citire atenta de verificare. Acest aspect nu poate fi suficient de mult accentuat. Daca partea publica a software-ului nu este corecta, cum ar putea cineva sa aiba incredere in corectitudinea interna a software-ului?

13 Interfete software

Cateva dintre cele mai interesante tipuri de utilitati software noi pentru computere personale sunt cunoscute drept "rezolvatoare de conflicte". Un rezolvator de conflict examineaza fisierele de configuratie software, cautand posibile inconsistente intre diferite aplicatii, sau chiar intre diferite versiuni ale aceleiasi aplicatii. Aceste utilitati incearca sa rezolve problemele care pot sa apara atunci cand software-ul se interfateaza cu un mediu cu diferite versiuni de sisteme de operare, compilatoare, utilitati sau programe aplicatie. Programele de detectare a rezolutiei conflictelor sunt rulate deseori de utilizatori frustrati de software-ul aparent corect care nu ruleaza corect, le determina caderea computerului sau chiar distrugerea de date create de alte programe aplicatie.

Bineinteles, aceleasi probleme pot sa apara atunci cand un sistem software este creat din componente software individuale. Nevoia determinata de piata de a lansa versiuni de actualizare la intervale de cateva luni plaseaza un accent puternic asupra reutilizarii software si asupra componentelor software de nivel inalt, incluzand subsisteme complete. Aceasta, la randul ei, poate conduce la probleme semnificative cu interfete intre subsisteme. Din moment ce aceste interfete nu sunt deseori vazute de utilizatori ai software-ului, rezultatele conflictelor si a inconsistentelor nu sunt in mod evident clare, in special utilizatorilor ocazionali sau neexperimentati.

Multe organizatii de dezvoltare software creeaza un document formal, de obicei cunoscut drept "document de control al interfetei", sau ICD (interface control document), pentru a ajuta manipularea interfetelor intre componente software sau subsisteme. Un ICD tipic pentru un proiect foarte mic va include numele fiecarui subsistem major, impreuna cu o descriere formala a interfetelor dintre ele. Interfetele pot fi atat de simple precum numarul, tipul si utilizarea fiecarui argument catre o functie, tipul si utilitatea fiecarei valori returnate, precum si orice efecte secundare ale operatiilor unei functii, in special in cazul unor conditii de eroare.

In aplicatii mai realiste, ICD va fi cu mult mai elaborat. Frecvent, ICD-ul este dat ca o matrice, unde liniile si coloanele sunt etichetate cu numele subsistemelor sau componentelor majore. Intrarile matricei sunt deseori nume de documente care descriu interfetele reale mai amanuntit decat poate fi facut acest lucru intr-un spatiu mai mic.

De exemplu, un ICD pentru un proiect cu trei subsisteme numite A, B si C, poate arata astfel:

Sistem A

Sistem B

Sistem C

Sistem A

Doc 2.0

Doc 2.3

Sistem B

Doc 1.1

Sistem C

Exista un anumit aspect care trebuie mentionat. Unul dintre beneficiile pretinse de analiza si proiectarea orientata pe obiecte este separarea interfetei obiectelor de implementarea lor. Un proiect de dezvoltare software care determina interfata publica a obiectelor majore intr-un sistem intr-un stadiu de inceput al procesului va permite implementarea atat a obiectului a carui interfata este publicata, cat si a tuturor obiectelor care folosesc acea interfata pentru a actiona cu nevoie redusa de coordonare aditionala. Dezavantajul este ca, in timp ce interfetele intre obiecte mici sunt usor de determinat, sunt greu de descris interfetele dintre componentele majore ale subsistemelor.

Remarcam ca interfetele software sunt cel mai usor de manipulat atunci cand componentele software sunt in acelasi domeniu al aplicatiei, deci exista control asupra componentelor sau interfetelor subsistemului. Standarde stabilite dintr-un anumit domeniu de aplicatie contribuie cu succes la reutilizabilitate. Atunci cand exista standarde intarite, pot sa apara urmatoarele lucruri bune:

Problema reutilizarii de cod sursa in cadrul unui domeniu devine mai usor de manipulat, din moment ce domeniul este mai probabil sa fie unul redus

Componentele bibliotecii au o probabilitate mai mare de a fi reutilizate daca nu sunt folosite standarde

Exista putine tipuri de date si partile reutilizabile sunt mici, fiind astfel mai probabil ca acestea sa fie reutilizate in mai multe aplicatii.

Costul dezvoltarii si mentinerii este redus datorita nevoii mai mici de a scrie filtre sau "elemente de lipire" intre diferite componente.

Utilizarea interfetelor standard presupun ca deciziile luate pentru un modul sau subsistem nu ar trebui sa intre in conflict cu alt module sau subsisteme.

Cateva standarde sunt mai usor de determinat decat altele. De exemplu, stocarea tipurilor fundamentale precum caractere, intregi si numere in virgula flotanta ar putea fi diferite in limbaje diferite sau chiar compilatoare diferite ale aceluiasi limbaj. Miscarea spre internationalizarea seturilor de caractere poate cauza dificultati mari pentru interactiunea cu software-ul intentionat pentru un set larg de caractere (tipul w_char) ale versiunilor mai noi ale lui C cu versiuni mai vechi in care simpla declaratie (tipul char) este suficienta. Aceste deosebiri pot fi gasite prin cautarea in fisierele cod sursa ale prezentei unor cuvinte precum w_char.

Pe de alta parte, poate fi mai greu sa determinam daca doua componente software prelucreaza datele corect. De exemplu, o componenta ar putea stoca datele ca set de trei intregi, pentru zi, luna si an. Alta ar putea rezerva spatiu folosind doar sase caractere in forma zzllaa. Rutinele de conversie, impreuna cu limitarile determinate de presupunerea implicita ca doua caractere ar fi intotdeauna suficiente pentru a reprezenta un an nu sunt triviale, in special daca datele sunt folosite in multe moduri diferite in cadrul componentelor software. Bineinteles, vom avea dificultati majore cu problema anului 2000.

Intrebarea de baza care poate fi pusa despre interfetele intre diferite componente software este:

Au fost dezvoltate componentele software in concordanta cu standardele de codificare?

S-a realizat documentatia pentru fisierele de configurare si fisierele antet necesare?

Componentele software sunt de calitate inalta?

Cat efort trebuie depus pentru a incorpora componentele intr-un sistem?

14 Cateva metrici pentru proiectare

Scopul acestei sectiuni este de a va prezenta ideea de masurare a proiectarii sistemelor software. Din pacate, foarte putine abordari sunt standard in acest domeniu si exista putine rezultate de cercetare definitive, precum e cazul majoritatii metricilor eficiente. Nu in ultimul rand, pare clar ca vom creste accentul asupra metricilor care pot oferi indrumari managerilor de evaluare a proiectelor. Corespunzator, putem oferi cateva sugestii pentru manageri asupra acestei teme.

O grija majora a managerilor software in acest punct al procesului de dezvoltare software este modularitatea proiectelor lor. Din acest motiv, va sugeram urmatoarele metrici de masurare a marimii interfetelor dintre subsisteme in stagiul de proiectare:

O masurare posibila ar fi o numarare a functiilor, modulelor, subsistemelor sau componentelor sistemului.

O alta masurare posibila este o numarare a obiectelor, functiilor, modulelor, subsistemelor sau componentelor cu care trebuie sa se interfateze fiecare componenta.

O alta masurare posibila este o descriere a marimii interfetelor dintre functii diferite, module, subsisteme sau componente. Aceasta masurare poate include o numarare a variabilelor partajate, sau poate fi marita pentru a include o evaluare a complexitatii variabilelor partajate.

In continuare, o alta masurare posibila este numararea ciclurilor intr-un graf de control al fluxului folosit pentru a descrie proiectul unui sistem.

Exista cateva metrici evidente pe care un manager de proiect le poate aplica proiectului produs de echipa de proiectare. Metrica punctelor de functionare pe care am discutat-o in Capitolul 3 poate fi folosita in acest stadiu pentru a oferi o evaluare a dificultatii implementarii proiectului.

Un proiect (design) care incurajeaza productivitatea inalta prin intermediul reutilizarii ar trebui sa se asigure ca diferite componente software au interfete standard. Gradul de aderenta la standarde este de asemenea important si masurabil pana la un anumit nivel.

Scopul metricilor aici este de a produce un proiect cat de simplu posibil, cu o cuplare minimizata intre subsisteme. Metricile care calculeaza gradul de interconectare dintre subsisteme sau module diferite ar trebui colectate. Proiectele de sistem cu interfete intinse ar trebui revizuite pentru a reduce costurile de integrare si testare.

Metricile de cost pot fi foarte importante in faza de proiectare. Estimarile de cost pentru sistemele anterioare construite folosind design-ul ce va fi reutilizat ar trebui comparate cu costurile reale pentru implementarea proiectului si orice deviatii neobisnuite ar trebui notate si explicate.

Poate ca Dvs. puteti sa sugerati si alte metrici. Sugerarea metricilor pentru proiecte este usoara; sarcina grea este de a colecta metricile si analiza datele colectate pentru a determina daca metricile descriu cu adevarat cateva aspecte ale unui sistem.

Proiectul Dvs. de dezvoltare poate dezvolta alte metrici de proiectare in functie de experienta organizatiei si mediul de dezvoltare preferat.

15 Revizuiri ale proiectului

Amintiti-va ca un tel major al unui manager software este de a prezice riscuri intr-un proces de dezvoltare software. El ar dori sa minimizeze in intregime riscurile. Astfel, exista un accent puternic asupra acelor activitati pe care managerul le considera ca vor reduce riscurile si vor permite ca software-ul curent sa fie creat pentru a indeplini specificatiile clientului si a asigura ca intregul proiect va fi incheiat la timp si in cadrul bugetului.

Astfel, managerul se poate astepta la doua lucruri: o revizuire detaliata a proiectului si un anumit tip de inspectie. In multe organizatii vor exista diferite revizuiri ale design-ului, deseori cu viziuni crescator detaliate ale design-ului prezentat.

Revizuirile proiectarii au multe in comun cu revizuirile cerintelor. Ele sunt extrem de importante pentru succesul unui proiect. Necesita planificare considerabila si consum considerabil de timp si resurse.

Exista cel putin o diferenta fundamentala intre revizuirile cerintelor si cele ale proiectarii. Intr-o revizuire a unui proiect detaliat care este realizata corespunzator, proiectul va fi deseori examinat pentru a fi siguri de ce se poate intampla daca sistemul a fost folosit intr-un mod necorespunzator. Cu alte cuvinte, proiectarea poate fi verificata pentru a ne asigura ca sistemul evita propagarea erorilor ce apar intr-un anumit modul al unui subsistem catre alte module ale altor subsisteme.

Tabelul 4 ilustreaza aspecte ce trebuie urmarite in revizuirea unui proiect.

Tabelul 4

Aspecte urmarite pentru revizuirea unei proiectari

Prezentarea ar trebui recapitulata.

Timpul prezentarii trebuie sa se incadreze in limitele alocate.

Trebuie alocat suficient timp pentru intrebari.

Persoanele care pot sa raspunda la intrebari tehnice trebuie sa se afle in auditoriu

Toate slide-urile, foliile si materialele multimedia trebuie verificate pentru acuratete

Toate slide-urile, foliile si materialele multimedia trebuie verificate semantic.

Copiile pe hartie, foliile si materialele multimedia trebuie puse la dispozitia participantilor.

Cineva trebuie sa verifice ca incaperea sa detina toate echipamentele necesare: microfoane, retroproiector, videoproiector, aparat video si monitor, cabluri etc.

Trebuie sa circule prin sala o lista pentru inscrierea numelui, adresei, numerelor de telefon si afilierii fiecarui participant, iar toti cei care participa trebuie sa se inscrie.

Un ultim pas care devine tot mai uzual in practica de inginerie software este plasarea fie in cadrul retelei locale a organizatiei, fie pe Internet a oricarui document de proiectare aprobat (prelimiar, intermediar, final). Documentele de proiectare pot fi avea o forma atat de simpla precum un set de fisiere create cu un procesor de texte. Ele pot include diagramele de design ale proiectului realizate in formatul unei unelte de desenare. Ele pot fi si imagini foto digitale ale altor documente stocate intr-un format precum un fisier .gif. In cazuri extreme, anumite documente pot fi stocate in formate animate precum fisiere .jpg sau .mpg.

De ce sunt publicate electronic documentele de proiectare in multe organizatii? Motivul este simplu: oamenii isi pierd documentele de hartie o data cu deplasarile personale, relocarile de birouri, si de obicei doresc sa reduca dezordinea din birou. In plus, documentele disponibile in retea pot fi folosite de orice persoana care are acces securizat la fisiere.

16 Punctul de vedere al unui manager asupra proiectarii

Asa cum am indicat in sectiunea anterioara, este probabil ca managerul unui proiect sa se astepte la doua lucruri: o revizuire detaliata a proiectului si un anumit tip de inspectie. In multe organizatii, vor exista diferite revizuiri ale proiectului, deseori cu viziuni crescator detaliate ale proiectarii prezentate. Managerul va considera aceste revizuiri ca fiind extrem de importante.

Managerul de proiect va dori ca fiecare element al matricii de urmarire a cerintelor sa fie verificat alaturi de proiectarea detaliata, pentru a se asigura ca cerintele scrise ale sistemului vor fi indeplinite de fiecare sistem software posibil care poate fi implementat in concordanta cu acest design detaliat.

Datorita faptului ca evaluarea performantei muncii unui manager de catre supervizorii sai depinde deseori de finalizarea cu succes a unui proiect, managerul prudent va incerca sa foloseasca metode cantitative de determinare a stadiului proiectului sau. Metricile se pot caracteriza ca fiind folosite pentru a masura un produs precum un design, sau procesul prin care produsul a fost creat. Am discutat metrici pentru a descrie artefacte ale proiectarii in sectiunea 1

Un manager poate aplica anumite metrici pentru a evalua eficienta procesului de creare a unui proiect de succes. El poate compara numarul de persoane care lucreaza in cadrul echipei de proiectare pentru acest proiect cu cazul proiectarii altor proiecte similare pentru a obtine evaluari informale ale eficientei echipei de proiectare. Numarul de revizuiri ale proiectarii poate fi un factor negativ daca echipa de proiectare nu pare sa progreseze in iterarile succesive ale proiectarii.

Managerul va cere ca echipa de proiectare sa lucreze la publicatiile tehnice ale organizatiei pentru a se asigura ca proiectarea adera la formatele standard ale companiei sau clientului.

17 Arhitectura Proiectului Major de inginerie a programarii

Suntem acum pregatiti sa descriem arhitectura proiectului major de inginerie a programarii pe care il vom studia in restul acestui curs. Pentru a va reimprospata memoria, ar trebui sa va uitati la matricea de urmarire a cerintelor pentru sistemul pe care l-am dezvoltat in Capitolul 3. Pentru a face arhitectura mai usor de inteles, ne vom concentra asupra celor mai relevante tipuri de arhitecturi. De asemenea, ne vom preocupa cu combinatii de reprezentari textuale si grafice, mai degraba decat a ne limita la UML, pentru ca dorim sa facem procesul cat mai general posibil.

Amintiti-va ca exista diferite tipuri de arhitecturi:

Arhitectura fizica

Arhitectura logica

Arhitectura functionala

Arhitectura software

Arhitectura tehnica

Arhitectura de sistem

Arhitectura de desfasurare

Vom incepe cu cea mai usoara idee. Software-ul trebuie sa ruleze pe cateva versiuni ale sistemului de operare Windows. Din acest motiv, putem folosi facilitati disponibile in Windows pentru a interfata sistemul de operare. De asemenea, daca computerul se afla in retea, putem folosi reteaua pentru a separa calculele dintre client si server, sau dintre mai multi clienti si servere. Cateva dintre optiuni sunt ilustrate in Figurile 24 si 25.


Figura 2 O posibila organizare, cu calcule multe ale clientului

Un avantaj al integrarii puternice a Windows Explorer cu sistemul de operare este ca mai multe interfete cu utilizatorul sunt aceleasi pentru sistemele in retea, ca si pentru sistemele independente. (aceasta integrare puternica a fost de altfel baza actionarii in instanta a companiei Microsoft de catre Guvernul SUA). Folosirea in comun a interfetelor cu utilizatorul face ca atat interfata cu utilizatorul cat si structura de comunicari interne a subsistemului computational sa fie puternic portabile in cadrul mediului Windows si relativ usor de a le face interoperabile cu ale sisteme (bazate pe Microsoft).


Figura 25. O proiectare alternativa, cu calculele realizate de server

Astfel, putem folosi ferestre de dialog existente pentru intrarile de fisiere cu foarte putine modificari, asa cum se ilustreaza in Figura 26 si 27. Prezenta casutei de dialog etichetate "drive" face sa fie clar ca putem accesa fisiere pe dispozitivele hard locale, pe dispozitive floppy locale si pe dispozitive ale altor computere din aceeasi retea.

Reamintiti-va ca arhitectura tehnica a sistemului presupune maparea software-ului la arhitectura fizica. Decizia trebuie luata in acest moment. Interfetele ilustrate in Figura 26 si 27 ilustreaza fezabilitatea aproape oricarei mapari la arhitectura fizica. Intr-o lume ideala, cu timp considerabil, multe arhitecturi alternative ar putea fi luate in considerare. In realitate, alegerea ar putea fi limitata la un set mai mic bazat pe decizia de a avea totul realizat pe un singur sistem sau pe un numar mic de clienti si servere.

Vom indica arhitectura sistem in Figura 28. Remarcam ca proiectarea arhitecturala ar trebui sa indice interactiunile cu sistemul de operare; in acest caz, daca folosim Java sau DLL-uri Microsoft existente. (Am ales DLL-uri) Restul arhitecturii ar trebui sa fie clara din citirea urmatoarelor doua sectiuni.

Figura 26. O ilustrare a unui posibil mod de interfatare a sistemului software cu un sistem de operare

Figura 27. O ilustrare mai detaliata a unui posibil mod de interfatare a sistemului software cu un sistem de operare


Figura 28. Viziune la nivel inalt asupra arhitecturii proiectului major de dezvoltare software

18 Proiectare preliminara a proiectului software major

Ne vom intoarce acum la o aplicatie a abordarii noastre de proiectare: continuarea proiectului software pentru care am dezvoltat cerinte in Capitolul 3. In aceasta sectiune, vom dezvolta atat proiecte preliminarii cat si detaliate ale exemplului nostru de sistem software. Exista mai multe intrebari pe care trebuie sa le raspundem daca dorim sa avem un design corespunzator ce va duce eventual la un sistem software care adera la scopurile de inginerie a programarii date in Capitolul 1.

Dorim sa dezvoltam un design care este usor de implementat intr-o maniera eficienta, pastrand in memorie scopurile ingineriei programarii enuntate in Capitolul 1. In acelasi timp, dorim ca design-ul nostru sa mapeze cerintele in sensul ca vom putea determina daca fiecare cerinta este indeplinita. Am lucrat cu o cantitate mare de informatie despre schemele software, reprezentarile proiectarii si numeroase tehnici. Volumul pur de material prezentat face dificil sa gasim punctul de pornire.

Vom incepe prin a potrivi cerintele problemei noastre cu una sau mai multe dintre schemele software enumerate in Sectiunea 2. Vom discuta aplicabilitatea fiecarei scheme in parte.

Prima schema descrie o interfata condusa de meniuri. Este in mod clar de neaplicat pentru ca dorim sa avem un sistem condus batch in versiunea initiala a software-ului.

A doua schema software descrie un sistem bazat pe evenimente. O interfata cu utilizatorul condusa de evenimente este si ea in mod evident nepotrivita pentru sistemul discutat. Modelarea sistemului ca un set de stari ar putea fi posibila datorita procesarii de text necesare pentru a calcula liniile de cod. Totusi, pare putin probabil. Urmatoarele doua scheme folosesc si ele stari si par mai potrivite pentru scopurile noastre.

Schema numarul trei pare foarte tentanta datorita faptului ca un fisier cod sursa poate fi considerat ca fiind un stream de cadre eliminate din fisierul de intrare o data ce a fost procesat. Pare sa existe un numar mic de "stari" si un set mic de actiuni optionale care pot fi intreprinse pentru fiecare stare. Actiunea optionala depinde atat de stare cat si de valoarea unui "cadru" de intrare.

A patra schema pare mai putin promitatoare decat a treia, prin aceea ca decizia despre actiunea care trebuie intreprinsa poate depinde de mai multa informatie decat cea disponibila din perechea formata de stare si cadrul de intrare. In aceasta schema, cadrele pot sa ramana in streamul de intrare si dupa ce au fost procesate.

A cincea schema poate sugera un sistem baze de date. Aceasta poate fi potrivita pentru sistemul de comunicari interne ale software-ului. O foaie de calcul corespunde de asemenea acestei scheme.

A sasea schema, un sistem general, flexibil, configurabil, pare necorespunzatoare.

A saptea si a opta schema prezinta mai multe posibilitati rezonabile. Daca sistemul este ghidat primar in intregime de un algoritm, mai degraba decat sa depinda de date, atunci potriveste o abordare procedurala. Este cazul celei de-a saptea scheme.

Pe de alta parte, un sistem in care au loc multe actiuni de calcul relativ independente ar putea fi mai potrivit ca sistem orientat pe obiecte, caz in care folosim a opta schema.

Par sa existe cateva concluzii clare si aspecte asupra carora mai ramane sa luam o decizie. Tratarea intrarilor sistemului nostru software ca stream de cadre pare sa corespunda, asa cum o face si considerarea sistemului intern de comunicare ca baza de date, sau cel putin o interfatare cu o baza de date.

Din pacate, nu exista o optiune clara intre scrierea unui sistem orientat procedural sau a unui sistem orientat pe obiecte, cel putin in prima noastra tentativa de proiectare a sistemului.

Punctul de pornire este viziunea de nivel cel mai inalt al sistemului: arhitectura software a sistemului. Vom examina functionalitatea de baza a sistemului. Software-ul pare sa aiba blocurile arhitecturale de baza descrise in Tabelul 5.

Tabelul 5

O prima lista de componente mari si arhitecturi software a proiectului software major

1. O interfata care va interactiona cu utilizatorul si va manipula fisierele de intrare ce vor fi analizate de sistemul nostru.

2. O interfata cu utilizatorul care va include interfata descrisa mai sus.

3. Un set de rutine de analiza pentru evaluarea fisierelor de intrare oferite in pasul unu. Rutinele de analia vor calcula liniile de cod pentru fiecare functie si alte informatii necesare.

4. Rutinele de iesire ce interfateaza o baza de date sau foaie de calcul pentru analiza ulterioara.

5. Un program de baze de date sau foi de calcul pentru a realiza analize statistice aditionale si stocari de date pentru iesirea obtinuta in pasul patru.

Aceste activitati par sa epuizeze functionalitatea de baza a sistemului. Ne intoarcem acum la problema de reprezentare a acestor activitati de nivel inalt pentru a dezvolta un proiect initial si a ne permite sa imbunatatim proiectarea initiala prin iterare. Un design preliminar, orientat pe obiecte este dat in Figura 29.


Figura 29. Un design preliminar, orientat procedural pentru proiectul software major

Acest grafic al fluxului reprezinta intentiile cerintelor proiectului nostru software. Exista o interfata comuna, o determinare a tipului fisierelor cod sursa folosite la intrare, o separare a functionalitatii in trei subsisteme de analiza diferite, o rutina comuna de colectare a datelor si o interfata cu un program de baze de date sau foi de calcul.

Bineinteles, nu ar trebui sa ne multumim cu aceasta proiectare preliminara, din moment ce avem flexibilitate. Nici o metodologie de proiectare particulara nu poate fi impusa de angajatorul nostru. Sa ne gandim cum ar putea sa arate o proiectare a fluxului orientat pe obiecte a aceluiasi sistem. O diagrama de flux de nivel 0 este ilustrata in Figura 30.


Figura 30. Un design preliminar al fluxului de date de nivel 0 a proiectului software major

Se pare ca reprezentarea proiectarii bazate pe fluxul de control ofera mai multe informatii decat reprezentarea folosind abordarea fluxului de control. Bineinteles, am putea ajunge la o concluzie diferita daca am fi folosit aceste doua reprezentari a proiectarii pentru a dezvolta mai multe proiectari. Reprezentarea fluxului de control din Figura 29 pare de asemenea sa conduca mai usor la o descompunere in subsisteme.

Am respins proiectarea orientata pe obiecte (neilustrata aici) a sistemului complet, din acelasi motiv. Astfel, vom folosi Figura 30 ca baza pentru proiectarea de nivel inalt a sistemului nostru, care se va baza pe proceduri. Vor exista cateva componente orientate pe obiecte, asa cum vom vedea. Remarcati ca aceasta proiectare nu intra in conflict cu matricea de urmarire a cerintelor data in Exemplul 3.6.

Acum ar fi rezonabil sa examinam orice utilitati software, programe complete, unelte integrate sau alte resurse care pot fi folosite ca parte a sistemului nostru. Daca putem gasi astfel de utilitati, programe sau unelte, atunci putem sa usuram dezvoltarile viitoare prin refolosirea acestora. Orice utilitar software reutilizabile poate simplifica procesul de proiectare prin eliminarea nevoii de functionalitate detaliata a design-ului oferita de unealta sau utilitar. (in plus, nevoia de codare a functionalitatii oferita de unealta sau utilitar este de asemenea evitata printr-o asemenea reutilizare).

Sugeram o examinare a urmatoarei resurse disponibila pe Internet, la adresa:

https://www.qucis.queensu.ca/Software-Engineering/Cmetrics.html

Acest site include intrari pentru mai multe programe diferite. Il citam pe Lott (care mentine acest site):

"csize: O unealta pentru a masura marimea programelor C, scrisa de Christopher Lott in 199

cyclo: O unealta de analiza a complexitatii ciclomatice a unei secvente de cod ANSI sau C++, scrisa de Roger Binns in 1993. Poate genera un grafic postscript al fluxului pentru functii.

lc: O unealta pentru numararea liniilor de cod a fisierelor C, scrisa de Brian Marick in 1983 si actualizata in 1992.

hp_mas: Mas are o unealta de evaluare a mentenabilitatii pentru analiza programelor C dezvoltate cu finantarea lui Hewlett-Packard Corporate Engineering, la Universitatea din Idaho in 1992.

metre: O unealta de metrica-software si unealta de graf de apeluri pentru ANSI/ISO Standard C, scrisa de Paul Long in 1994 si actualizata in 1995.

metrics: O colectie de unelte (control, Halstead, KDSI, McCabe) constituita de Brian Renau prin 1989.

spr: O unealta de masurare NCSS pentru programe sursa C, scrisa de Ted Shapin in 1989.

Le-am construit cu succes pe toate cu gcc pe un Sun, folosind SunOS 1.3. Pentru pachetele ,csize' si ,metre', autorii au depus mult efort pentru a scrie cod portabil si Makefile-uri (fisiere de creare) flexibile. Pentru ,cyclo' si ,c-metr-pack', un asemenea efort nu a fost depus, si in consecinta a trebuit sa ma prostesc cu cateva fisiere de creare. Pachetele ,lc' si ,spr' sunt relativ simple si nu ar trebui sa prezinte probleme.

Totusi, nu am folosit toate uneltele extensiv, deci din pacate nu pot sa fac afirmatii ajutatoare referitor la stabilitatea sau usurinta folosirii lor."

Acest citat evidentiaza ceea ce ar trebui sa inteleaga toti utilizatorii de resurse sau produse gratuite: nu exista garantii. In limbajul reutilizarii software, pachetele software de pe acest site nu au fost certificate cu exceptia abilitatii de compilare a acestora pe un computer Sun care ruleaza un sistem de operare SunOS 1.3 (cunoscut si drept Solaris 1.1, care difera foarte mult de versiuni ulterioare Solaris).

Am realizat o alta cautare. De data aceasta, am examinat catalogul WSRD a bibliotecii de reutilizare mentinuta de SAIC (Scientific Applications International Corporation - Corporatie Internationala a Aplicatiilor Stiintifice). Aceasta biblioteca poate fi gasita la:

https://source.asset.com

Catalogul WSRD a listat 171 de rezultate la cautarea "software metrics". Dintre acestea, multe reprezentau materiale de documentare, materiale educationale, legaturi la unelte comerciale precum componente Grace din EVB Software, sau altele similare. Cateva unelte software gratuite au fost gasite disponibile prin ftp-ul anonim al programului STARS (Software Technology for Adaptable Reliable Software - Tehnologie Software pentru Software Adaptabil si Stabil).

Evaluarea noastra a pachetelor software Ada disponibile sugereaza ca unele dintre ele pot fi folosite pentru portiuni de analiza a sistemului software ce se dezvolta. Specific, ar putea fi folosita in analiza fisierelor cod sursa Ada. Totusi, ele ar trebui extinse pentru a realiza analiza fisierelor cod sursa Ada de care avem nevoie pentru a atinge specificatiile proiectului. Aceste unelte software produc de asemenea mult prea multa informatie neesentiala ce trebuie folosita ca atare.

In timp ce nu am examinat uneltele software existente mentionate detaliat anterior, avem suficienta informatie pentru a crede ca unele dintre ele ofera suficient de multa functionalitate pentru a satisface proiectul nostru. Chiar daca evaluarea preliminara a calitatii uneltelor reutilizabile este incorecta, putem folosi existenta uneltelor ca ghid in cadrul design-ului nostru. Cu alte cuvinte, analiza calitatii uneltelor software reutilizabile existente poate fi amanata pana la faza de codificare a proiectului. Nu trebuie sa garantam calitatea uneltelor in acest moment pentru ca ele nu afecteaza proiectarea (deocamdata).

Revenim acum la problema transformarii design-ului de nivel inalt reprezentat in Figura 30 intr-un design mai detaliat care este complet in sensul ca interfetele dintre componentele sistemului sunt bine intelese si functionalitatea fiecarei componente software este prezentata suficient de detaliat. Design-ul final ar trebui sa fie suficient de detaliat pentru a putea fi implementat fara dificultati prea mari.

Primul pas este de a lua in considerare interfetele dintre diferite subsisteme. Ele par sa fie in numar de sase subsisteme complete in cadrul sistemului (vezi enumerarea din Tabelul 6).

Amintiti-va ca inainte de a modifica cerintele de utilizare ale unui GUI, cerintele specificau ca interfata cu utilizatorul sa fie constituita din argumente in linia de comanda. Din moment ce am ilustrat fezabilitatea utilizarii casutelor de dialog existente pentru intrari de fisier, primirea fisierelor pare sa nu fie o problema.

Totusi, exista o problema care poate sa apara daca sistemul trebuie folosit in practica. Cerintele sistemului au specificat expres ca intrarile nu trebuie sa fie verificate. Astfel, nu trebuie sa ne ingrijoram in aceasta varianta a proiectului de faptul ca cineva ar folosi sistemul cu un fisier executabil ca intrare. Dificultatea consta in aceea ca sistemele software realiste sunt de obicei distribuite prin mai multe directoare diferite, astfel ca sistemul nostru software poate sa primeasca o intrare ce reprezinta un director. Cum putem incorpora procesarea directoarelor in proiectarea acestui software?

Tabel 6

Setul de subsisteme in proiectarea initiala a proiectului nostru software major

Subsistemul pentru interfata cu utilizatorul.

Subsistemul pentru obtinerea fisierelor si analizarea tipurilor de fisiere.

Subsistemul pentru transmiterea fisierelor de intrare catre subsisteme de colectare a datelor.

Subsistemul pentru colectarea datelor pentru fiecare fisier de intrare.

Subsistemul pentru transmiterea datelor catre foi de calcul sau baze de date.

Program pentru foi de calcul sau baze de date.

Exista cateva probleme, depinzand de cunostintele noastre referitor la sistemul de operare pe care va fi folosit sistemul nostru software si standardele de denumire despre care putem sa presupunem ca au fost folosite. (standardele de denumire vor fi discutate in detaliu in Capitolul 5, la discutarea problemelor de codare)

Vom face urmatoarele presupuneri despre conventiile referitoare la fisierele de intrare:

Toate fisierele de intrare scrise in C au nume care se termina cu extensii .c sau .C

Toate fisierele de intrare scrise in C++ au nume care se termina cu extensii .cpp sau .C

Toate fisierele de intrare scrise in Ada au nume care se termina cu extensii .a, .A sau .ada

Toate fisierele antet C sau C++ au nume care se termina cu .h si nu vor fi procesate mai departe

Orice fisiere numite Makefile sau makefile sunt instructiuni de compilare si nu vor fi procesate in continuare

Orice fisiere numite readme, read.me, README, READ.ME, sau care se termina cu .doc sau .txt si nu vor fi procesate mai departe

Orice fisiere cu nume care se termina fie cu .exe sau .obj pot fi ignorate

Toate celelalte fisiere sunt directoare si pot contine cod sursa, precum si alte fisiere (aceasta presupune, de exemplu, ca orice alte "fisiere speciale" precum drivere de device in UNIX vor fi ignorate)

Presupunerea ca codul sursa de intrare a fost dezvoltat folosind o conventie de denumire face ca proiectarea acestei portiuni a subsistemului sa fie usoara. Primim doar fisierele de intrare si le transmitem urmatorului subsistem. In cazul unui director, care poate fi determinat prin faptul ca numele sau nu se potriveste cu una din celelalte posibilitati, trebuie sa cautam de asemenea si in interiorul directorului. Cautarea fiecarui director ar trebui sa fie recursiva, astfel ca fisierele sursa localizate in directoare care includ alte directoare sa fie analizate.

O privire scurta asupra setului de baza de subsisteme sugereaza ca primele doua subsisteme pentru interfata cu utilizatorul si pentru obtinerea fisierelor si analizarea tipurilor de fisiere trebuie combinate. Acesta este rezultatul natural al presupunerii noastre ca s-au urmat conventiile de denumire enumerate anterior in crearea fisierelor de intrare catre sistemul nostru. Subsistemul pentru transmiterea fisierelor de intrare catre subsistemele de colectare de date par de asemenea redundante. Astfel, si ele pot fi combinate cu subsistemele initiale. In consecinta, cele sase subsisteme enumerate in Tabelu 6 pot fi combinate in cele patru subsisteme enumerate in Tabelul 7.

Tabel 7

Setul final de patru subsisteme pentru proiectarea proiectului nostru software major

Subsistemul pentru interfata cu utilizatorul, obtinerea fisierelor si analiza tipurilor.

Subsistemul pentru colectarea datelor pentru fiecare fisier de intrare.

Subsistemul pentru transmiterea datelor catre foi de calcul sau baze de date.

Program pentru foi de calcul sau baze de date.

19 Proiectarea subsistemelor pentru Proiectul Software Major

Sa incercam sa proiectam primul nostru subsistem. Ca o baza, vom folosi diagrama de flux de control data in Figura 31. Portiunile superioare ale proiectului sunt adecvate scopurilor noastre, cu exceptia faptului ca ele nu indica actiunile care vor fi intreprinse ca raspuns al tipurilor specifice de intrari. Cu alte cuvinte, diagrama din Figura 31 nu indica un mecanism pentru verificarea tipurilor de fisiere de intrare, pentru a determina daca exista fisiere director ce pot fi analizate mai departe, fisiere care pot fi ignorate, sau daca exista vreun fisier de intrare.

Amintiti-va ca documentul de cerinte pentru proiectul nostru software major specificau posibilitatea folosirii caracterelor generative (precum asteriscul) drept nume ale fisierelor cod sursa de intrare. Aceasta va crea anumite probleme de implementare pentru ca va presupune interactiunea cu procesorul de comenzi a sistemului de operare pentru a analiza liniile de comanda si traduce caracterele generative in nume de fisiere reale. Totusi, putem proiecta aceasta portiune a software-ului cu atentie atata timp cat stim cum stocheaza de fapt sistemul de operare argumentele liniei de comanda si le face disponibile programelor C sau C++. Astfel, determinarea acestei informatii este parte esentiala a procesului de proiectare in acest punct. Proiectul trebuie sa ia in considerare daca realizarea oricarei interactiuni cu sistemul de operare este posibila.

Subsistemul de colectare a datelor pentru fiecare fisier de intrare se va baza pe uneltele software existente localizate pe Internet, discutate anterior in aceasta sectiune. In mod specific, vom examina fiecare dintre aceste unelte ca functionalitate si le vom determina interfetele. Daca functionalitatea este suficienta pentru cerintele proiectului, vom oferi apoi o interfata catre unealta. Daca nici una dintre aceste unelte nu are functionalitatea corespunzatoare, atunci cel putin cateva dintre portiunile software-ului ce vor oferi functionalitatea necesara vor fi scrise de la zero. Aceasta inseamna ca trebuie proiectata noua unealta software.

Am dori sa amanam decizia de scriere a noilor unelte software pe cat de mult posibil, accentuand un proces de dezvoltare software eficient, bazat pe reutilizarea software. Totusi, aceasta inseamna ca noua unealta software trebuie evaluata din trei puncte de vedere: functionalitate, calitate si interfata cu restul sistemului. Trebuie folosit aici un document de control al interfetei (ICD). De asemenea, daca este posibil ca uneltele software sa se modifice, trebuie sa instituim o forma de management de configurare.

Al treilea subsistem ce trebuie considerat va oferi conectarea si agregarea datelor din diferite unelte software reutilizate care formeaza marea parte a celui de-al doilea subsistem. Este clar ca uneltele individuale numara datele in moduri diferite. Astfel, avem nevoie de consistenta in definirea datelor si in modul in care datele vor fi transmise la subsistemul final, care este baza de date sau foaia de calcul.

Exista un alt punct care trebuie subliniat inainte de a proiecta al treilea subsistem. Mai multe unelte ar putea sa nu ofere informatia dorita. Astfel, ar putea exista diferite informatii care fie nu sunt disponibile, fie trebuie inlocuite cu o valoare implicita. Aceasta pare sa sugereze prezenta polimorfismului, care in schimb sugereaza o abordare orientata pe obiecte.

Intr-o abordare orientata pe obiecte, cel mai important pas este de a le determina. Amintiti-va pasii sugerati in Tabelul 2 pentru determinarea obiectelor:

Alegeti un candidat pentru obiect

Determinati un set de atribute si setul de valori posibile al acestora. Folositi o relatie are-o. Enumerati toate transformarile relevante ale obiectelor.

Dezvoltati un set initial de transformari asupra obiectului pentru a servi drept functii membre.

Determinati daca exista mai multe exemple despre obiect.

Aplicati o relatie este-o.

Folositi polimorfismul si supraincarcarea operatorilor (si functiilor) pentru a verifica daca am descris obiectele suficient de detaliat.

Folositi o relatie foloseste-o pentru a determina toate instantele relatiilor client-server sau bazat-pe-agent.

Revizuiti obiectele pentru a verifica daca sunt complete.

Repetati pasii 2-8 pentru toate combinatiile relevante de obiecte (triplete, cvadruple etc) pana cand rolul obiectelor a fost descris adecvat.

Exista cateva obiecte candidat ce pot fi considerate ca obiecte fundamentale: functii individuale, fisiere cod sursa, sau colectii de fisiere cod sursa in subsisteme. Asa ca si anterior, folosim termenul "functie" pentru a exprima "functie" sau "procedura". Vom examina fiecare dintre aceste optiuni in ceea ce priveste obiectele de baza.

Daca obiectul este "functie", atunci cele mai evidente atribute si valorile lor potentiale sunt:

Atribut

Valoare specifica

Nume

Sir de caractere

Marime

Intreg

Modul in care se localizeaza

Sir de caractere

Daca obiectul potential este "fisier cod sursa", atunci cele mai evidente atribute si unele valori potentiale sunt:

Atribut

Valoare specifica

Nume

Sir de caractere

Marime

Intreg

Numar de functii

Intreg

Lista de functii

Lista inlantuita de siruri de caractere

Modul in care se localizeaza

Sir de caractere

Daca obiectul este "subsistem", cele mai evidente atribute si valori sunt:

Atribut

Valoare specifica

Nume

Sir de caractere

Marime

Intreg

Numar de fisiere cod sursa

Intreg

Lista de fisiere cod sursa

Lista inlantuita de siruri de caractere

Trebuie sa stim formatul de intrare al foii de calcul sau al bazei de date. Pentru software-ul tabele de calcul MS Excel intrarea intr-o baza de date poate avea diferite forme, inclusiv, dar nelimitata la urmatoarele:

O foaie de calcul existenta, creata in Excel

O foaie de calcul creata intr-un alt program foaie de calcul pentru care sunt disponibile translatoare

Un fisier text cu virgule folosite ca delimitatori

Un fisier text cu tabulatori folositi ca delimitatori

Alegem sa folosim forma delimitata de virgule, datorita faptului ca este putin probabil ca numele fisierelor sa contina virgule. Din pacate, folosirea aici a virgulelor ca delimitatori ar putea crea mai multe probleme, pentru ca virgulele sunt semne de punctuatie valide. Majoritatea bazelor de date folosesc un caracter non-printabil ASCII precum Ctrl-R ca delimitator pentru a separa diverse campuri. Lasam detaliile proiectarii interfetei la o baza de date drept exercitiu.

Proiectarea ar trebui sa fie acum verificata in vederea consistentei interne conform principiilor discutate in Sectiunea 12. Asa cum am indicat aici, orice standarde de interfata ar trebui sa fie consistente cu cerintele software ale tuturor modulelor sau subsistemelor afectate de interfata.

Acum ca avem un proiect, este necesar sa verificam proiectarea dupa matricea de urmarire a cerintelor pentru proiect. Elementul 9 al matricii de urmarire a cerintelor apeleaza o rutina de instalare. Din moment ce nu am discutat acestea anterior, trebuie sa il includem acum in setul nostru de subsisteme ce trebuie proiectate. Subsistemul de instalare ar trebui sa fie relativ independent de alte subsisteme ale produsului software complet, din moment ce cerintele specifica faptul ca o singura marime a sistemului va fi produsa si, astfel, este necesara putina configurare. Remarcati ca schema software al unui sistem general, flexibil, puternic configurabil ar putea fi folosita pentru a caracteriza instalarea subsistemului. Cea mai noua versiune a matricii de urmarire a cerintelor este data in Figura 8.

Ati putea sa va intrebati daca avem nevoie de o legatura explicita catre un program de foi de calcul, precum MS Excel, sau daca iesirea poate fi obtinuta prin folosirea de diverse DLL-uri din biblioteca Microsoft. Bineinteles, cerintele afirma un lucru, si modificarea lor ar putea determina dificultati.

Totusi, daca ilustram fezabilitatea utilizarii acestor componente DLL intr-o revizuire a proiectarii, este posibil ca un potential client sa permita modificarea cerintelor. Modificarea cerintelor sistemului este uzuala intr-o lume software condusa de piata.

Tabel 8

Matricea de urmarire a cerintelor pentru proiectul major de inginerie software

Nr.    Cerinta

Proiectare

Cod

Test

Bazat pe Intel

D

Windows 95

D

IU(interfata cu utilizatorul) Windows 95

D

Consistent cu Excel 0

D

Sistem de o singura marime

D

1 MB Sistem

1 MB spatiu disc

floppy disc de 1.44 MB

Include instalare

D

Fara utilitar de decompresie

D

Un fisier de intrare la un moment dat

D

Marimea fiecarei functii

D

Marimea fiecarui fisier

D

Marimea sistemului

D

Calculeaza totalul

D

Dezvolta std pentru C, C++, Ada

D

Sistem orientat-batch

D

LOC definit precis

D

Masurare separata

D

Nu se verifica erorile la intrare

D

Interfata in C sau C++

D

Procesare batch

D

Numele fisierelor limitate la 8.3

D

Pot fi folosite caractere generative

D

Cod mort ignorat

D

Nu sunt necesare compilatoare speciale

D

Folosirea lui MS Excel 0

D

Trebuie de asemenea sa remarcam ca anumite aspecte implica setarea standardelor, si, astfel, nu au fost luate in considerare in acest punct al procesului de proiectare. Alte cerinte nu pot fi adresate complet in design in acest moment.

De exemplu, in acest moment nu putem determina precis marimea intregului sistem. Marimea uneltelor software pe care intentionam sa il folosim poate fi determinata corespunzator, pentru ca uneltele software exista deja.

20 Proiectarea detaliata a Proiectului Software Major

Urmatoarea activitate pentru proiectul nostru major de inginerie a programarii este de a "transa" proiectarile anterioare pentru a descrie detaliat sistemul. Cate detalii sunt necesare? Raspunsul este in esenta acelasi ca cel pe care l-am dat atunci cand discutam abordarea lui Daniel si Orna Berry a problemei de determinare a cerintelor software: cerintele se considera a fi complete si specificate suficient de detaliat atunci cand un programator are destula informatie pentru a-si putea da seama daca poate dezvolta un sistem pentru a indeplini aceste cerinte.

Deosebirea majora intre acest grad de detaliere a cerintelor si un nivel similar de detaliu in proiectare este ca folosirea limbajelor de nivel inalt ar putea face ca anumite detalii de implementare ale sistemului sa fie inutile. Alocarea resurselor pentru implementarea detaliata poate fi inutila datorita faptului ca anumite prototipuri de proiectare si diagrame GUI vor fi suficient de dezvoltate pentru a face ca eforturi ulterioare de implementare sa fie redundante.

Diagrama ilustrata in Figura 31 ilustreaza acest lucru. Aceasta diagrama ilustreaza interfata cu sistemul de operare si arata clar ca iesirea poate fi afisata intr-o simpla fereastra pop-up. Alte aspecte ale GUI sunt ilustrate in figura 32-3

Ce altceva trebuie specificat intr-un design detaliat? Trebuie sa vedem descrierile interfetelor, functionalitatea software-ului pe care il scriem ca "elemente punte" intre componentele obtinute de pe Internet si alte surse.

Pare probabil ca acest proiect sa fie potrivit pentru dezvoltare concurenta. Astfel, avem nevoie de un document de control al interfetei (ICD) pentru a ne asigura ca toti dezvoltatorii folosesc aceleasi interfete comune.

Din perspectiva managementului de proiect, ar trebui de asemenea sa facem o verificare a starii. Suntem inainte de termenul din calendar (puti probabil), am ramas in urma, suntem aproximativ la tinta? Au existat surprize neplacute, portiuni ale sistemului care au fost mai dificile decat ne-am asteptat? Exista portiuni ale sistemului care necesita atentie suplimentara, poate resurse aditionale? Au facut presiunile pietei sau tehnologiei ca anumite portiuni ale sistemului sa fie scoase din uz? Exista modificari care ar putea afecta capacitatea noastra de a termina acest proiect?

Figura 31. O ilustrare a iesirii sistemului. Iesirea este afisata intr-o fereastra cu casute de dialog suprapuse unei alte aplicatii.

Figura 32. O ilustrare a iesirii grafice a sistemului. Iesirea este afisata intr-o fereastra cu o singura casuta de dialog.

Figura 33. Casuta de dialog pentru controlul tipului de iesire a sistemului

Figura 3 Iesire detaliata a sistemului





Politica de confidentialitate





Copyright © 2024 - Toate drepturile rezervate

Informatica


Access
Adobe photoshop
Autocad
Baze de date
C
Calculatoare
Corel draw
Excel
Foxpro
Html
Internet
Java
Linux
Mathcad
Matlab
Outlook
Pascal
Php
Powerpoint
Retele calculatoare
Sql
Windows
Word


STANDARDE SI NORME PENTRU DOCUMENTELE ELECTRONICE
EVALUAREA SATISFACȚIEI CLIENȚILOR UTILIZATORI DE NOTEBOOK-URI TOSHIBA
Proiectarea Componentei de Interactiune cu Factorul Uman (interfetei utilizator)
Introducere in Maya - GRAFICA 3D
LISTE CIRCULARE SIMPLU INLANTUITE
Ceasul de timp real 1 (T/C1)
Program facturare - Manual de utilizare
INFORMATIZAREA PROCESULUI DIN CHE
NOTIUNI DE ALGEBRA LOGICA (BOOLEANA)
PROGRAME UTILITARE




termeni
contact

adauga