CATEGORII DOCUMENTE |
Modularitate, clase si metode
Majoritatea programelor, care rezolva probleme reale, sunt mult mai simple decat cele elaborate de noi pana in prezent. Experienta a aratat ca, in cazul programelor mari, este mult mai eficient (din punctul de vedere al proiectarii, testarii, depanarii si modificarii ulterioare) ca acestea sa fie concepute sub forma a mai multe module mai simple. Fiecare astfel de modul este mai usor de proiectat, testat si depanat decat un program mare. De asemenea un astfel de program modular poate fi mai usor modificat, prin modificarea unuia sau a catorva din modulele componente fara ca restul modulelor programului sa fie afectate. De asemenea programului astfel proiectat i se poate largi functionalitatea fara modificari majore prin adaugare de noi module. Aceasta metodologie de proiectare a programelor este cunoscuta sub denumirea divide et impera. In limbajul Java, modularitatea programelor este implementata prin metode si clase. Programele Java se elaboreaza prin combinarea metodelor "prefabricate" disponibile in bibliotecile de clase standard, furnizate impreuna cu compilatorul (asa cum ar fi metoda println a clasei System.out si pow a clasei Math deja folosite de noi in programele elaborate pana acum) cu metode si clase "prefabricate" elaborate de alti furnizori de software si cu metode si clase proprii, noi, create chiar de catre programator. Bibliotecile de clase standard ofera o bogata colectie de clase si metode pentru diverse calcule matematice, prelucrari de siruri de caractere, input/output, detectarea si tratarea erorilor in timpul executiei si multe altele. Aceasta usureaza mult munca programatorului care este degrevat de sarcina de a elabora algoritmi pentru diverse operatii de rutina (cum ar fi de exemplu ridicarea la putere a unui numar) putandu-se concentra pe rezolvarea problemei propriuzise. Modularitatea permite de asemenea programatorului sa elaboreze metode care pot fi folosite, de mai multe ori, in mai multe puncte din programului. asa ar putea fi de exemplu o metoda care sa realizeze calculul inversei unei matrici. Odata elaborata o astfel de metoda, ea va putea fi folosita ori de cate ori este nevoie sa inversam o matrice in cadrul programului. Instructiunile metodei se scriu o singura data, nu de fiecare data cand este necesara prelucrarea implementata de aceasta. In punctul din program unde este necesara aceasta prelucrare se plaseaza doar instructiunea de apel a metodei. Metoda este apelata prin specificarea numelui sau urmat de o lista de parametri incadrata de paranteze rotunde. metoda prelucreaza datele transmise ca argument returnand valoarea rezultata. Lucrurile se petrec asemanator cu situatia in care directorul cheama un subaltern ( il apeleaza prin intermediul numelui) si ii solicita sa duca la indeplinire o anumita sarcina inmanandu-i si un dosar cu informatia necesara indeplinirii acestei sarcini (lista de argumente). Salariatul prelucreaza informatiile din dosar si pe baza acestora intocmeste un raport cu rezultatele obtinute (valoarea returnata de metoda). Pentru a-si indeplini sarcina salariatul (daca este de exemplu sef de serviciu) poate apela la ajutorul altor subalterni impartind fiecaruia cate o parte din documentele continute in dosar sau documente intermediare obtinute pe parcursul prelucrarii documentelor primare. Seful va sintetiza rapoartele primite de la subalterni intr-un singur raport pe care il va returna directorului. Analog, o metoda apelata poate la randul sau sa apeleze alte metode pentru prelucrari intermediare. Am avut deja de a face cu apelarea unor metode cand am avut de efectuat afisari sau de ridicat numere la putere. Numele metodelor este un identificator construit dupa aceleasi reguli ca si numele variabilelor.
Asa cum am aratat si main este o metoda. De fapt este metoda principala a programului care este apelata automat de interpretor la inceperea executiei programului. in exemplele studiate de noi aceasta metoda a apelat la randul sau la alte metode cum ar fi println si pow pentru a face afisari sau pentru a ridica la putere un numar. In figura 5.1 este prezentat un exemplu al mecanismului de apel al metodelor intr-o maniera ierarhica sef-subaltern asa cum a fost descrisa mai sus.
Metodele clasei Math
Clasa Math pune la dispozitia programatorului o paleta larga de metode care ii permit efectuarea diverselor calcule matematice. Vom folosi aceasta clasa pentru a exemplifica utilizarea unor metode "prefabricate". pe parcursul cursului vom studia si alte metode din biblioteca standard de clase a limbajului Java (Java API - Applications Programming Interface). Asa cum am aratat mai sus, apelul unei metode se face prin numele sau urmat de o lista de argumente separate prin virgule si incadrata de paranteze rotunde. Instructiunea prin care se face apelul se termina cu terminatorul ";". De exemplu pentru a calcula radicalul din valoarea 2500 vom apela metoda sqrt ( de la square root - radacina patrata in limba engleza):
System.out.println(Math.sqrt(2500));
Cand instructiunea de mai sus este executata, este apelata mai intai metoda sqrt a clasei Math, cu argumentul 2500. Rezultatul - valoarea 50.0 de tip double - intoarsa de aceasta este convertit automat la tipul String si transmis ca argument metodei println a clasei System.out pentru afisare. Se observa ca la apel, numele este precedat de numele clasei din care face parte urmata de caracterul punct (.). Dupa caz, argumentele metodei pot fi constante, variabile sau expresii ca in exemplul de mai jos:
double a=12.5;
double b=6.25;
System.out.println(Math.sqrt(a+2*b));
Dupa ce va evalua expresia a+2*b, obtinand valoarea 25.0, instructiunea va calcula si afisa valoarea radicalului din aceasta adica 5. In tabelul urmator sunt specificate cateva din metodele uzuale ale clasei Math:
Metoda |
Descriere |
Exemplu |
abs (x) |
Valoarea absoluta a lui x. Aceasta metoda are versiuni pentru argumente int, float,double si long |
daca x>=0 abs(x) este x daca x>=0 abs(x) este -x |
ceil (x) |
rotunjeste prin adaugare valoarea lui x la cel mai apropiat intreg |
ceil( 9.1 ) este 10 ceil( -9.9 ) este -9 |
cos (x) |
calculeaza functia trigonometrica cosinus a lui x exprimat in radiani. |
cos(0) este 1 |
exp(x) |
calculeaza functia exponentiala ex |
exp(1) este 2.71828 |
floor (x) |
rotunjeste prin trunchiere valoarea lui x la cel mai apropiat intreg |
floor( 9.9 ) este 9 floor( -9.1 ) este -10 |
log (x) |
calculeaza functia logaritm natural din x. |
log(2.718282) este 1 |
max (x,y) |
intoarce valoarea argumentului maxim |
max( 1.5 , 3.1) este 3.1 |
min ( x,y ) |
intoarce valoarea argumentului minim |
min( 1.5 , 3.1) este 1.5 |
pow (x,y) |
calculeaza valoarea lui x ridicat la puterea y, x y |
pow (2,7) este 128 pow ( 9, .5 ) este 3 |
sin (x) |
calculeaza functia trigonometrica sinus a lui x exprimat in radiani. |
sin(0.0) este 0 |
sqrt( x) |
calculeaza radicalul din x |
sqrt ( 9.0 ) este 3 |
tan (x) |
calculeaza functia trigonometrica tangenta a lui x exprimat in radiani. |
tan(0.0) este 0 |
De asemenea clasa Math defineste doua constante folosite frecvent in calcule si anume numarul Math.PI egal cu 3.14159265358979323846 si numarul e, Math.E egal cu 2.718282818284590452354.
Metode
Definirea unor metode proprii permite programatorului sa-si modularizeze programul. Toate variabilele declarate in cadrul metodelor sunt variabile locale, existente si vizibile (cunoscute) numai metodei in care au fost declarate. Cu alte cuvinte aceste variabile nu pot fi accesate decat de metoda in care au fost ele declarate. Asa cum am vazut deja, comunicarea metodei cu metoda apelanta se poate face prin lista de argumente (parametri) specificate in antetul metodei. Parametrii metodei sunt de asemenea locali, cunoscuti numai ei, fiind similari variabilelor locale. Daca aceasta metoda va apela o alta metoda aceasta din urma nu va avea acces direct la parametrii primeia. Ea va trebui sa primeasca de la metoda apelanta datele sale initiale prin propria lista de parametri.
Exista mai multe motive pentru modularizarea programelor. In primul rand abordarea proiectarii programului pe principiul divide et impera faciliteaza munca programatorului in toate etapele elaborarii programului (proiectare, testare, depanare si modificare). In al doilea rand modulele elaborate pot fi proiectate astfel incat sa poata fi refolosite si la elaborarea altor programe. In al treilea rand utilizarea metodelor ne permite sa evitam repetarea unor secvente de instructiuni identice in cadrul aceluiasi program. O astfel de secventa poate fi "impachetata" in corpul unei metode si apelata din orice punct al programului, acolo unde este necesara prelucrarea respectiva.
Definirea metodelor
Pina acum am folosit in programele elaborate metodele unor clase "prefabricate" din biblioteca de clase Java API. De fapt, am definit deja in toate programele noastre o metoda si anume metoda main care, am invatat noi, ca nu trebuie sa lipseasca din nici o aplicatie Java. Celelalte metode ale unei clase au o sintaxa similara metodei main. Definirea minimala a unei metode are deci sintaxa:
<tipul valorii returnate><numele metodei>( <lista de parametri> )
<numele metodei> trebuie sa fie un identificator valid ( respectand regulile deja cunoscute de noi - sa inceapa cu o litera si sa nu contina decat cifre si litere).
<tipul valorii returnate> este tipul valorii returnate de metoda. daca metoda nu intoarce o valoare acest tip este void.
<lista de parametri> este o lista de declaratii separate prin virgule ale parametrilor metodei avand forma:
<tip><nume >,<tip><nume >, , <tip><nume >
unde <tip> este tipul iar <nume> numele (identificatorul) parametrului.
Daca metoda nu are nevoie sa primeasca valori pentru prelucrare ca parametri, aceasta lista este vida, nu contine nici un termen. Cu alte cuvinte intre paranteze nu se inscrie nimic. Blocul de instructiuni cuprinse intre acolade se numeste corpul metodei.
Exista trei modalitati de a termina executia metodei si de a reveni la metoda apelanta.
In cazul in care metoda nu trebuie sa intoarca un rezultat (este de tipul void), se poate cere explicit revenirea la metoda apelanta prin instructiunea:
return;
Aceasta instructiune poate fi plasata oriunde in corpul metodei si determina la executie terminarea imediata a metodei si revenirea la metoda apelanta.
Daca metoda trebuie sa intoarca o valoare ca rezultat atunci terminarea executiei si revenirea la metoda apelanta se face cu instructiunea :
return <expresie>;
metoda va intoarce valoarea rezultata din evaluarea expresiei <expresie>.
Daca metoda nu trebuie sa intoarca un rezultat (este de tipul void) si nu se executa o instructiune return pentru o revenire explicita, metoda se termina implicit la executarea ultimei instructiuni din corpul sau, controlul fiind cedat automat metodei apelante.
Pentru exemplificarea modului de definire si a avantajelor utilizarii metodelor sa analizam urmatoarele 2 probleme:
1. Se citesc trei litere de la tastatura. Programul va determina si va afisa litera cu codul maxim din cele trei citite.
Vom elabora intai programul fara sa folosim abordarea pe principiul divide et impera, fara sa folosim metode. Totusi chiar si in aceasta abordare suntem nevoiti pentru operatiile de I/O sa apelam metodele oferite de Java API in biblioteca (numita package - pachet) java.io. Ca sa informam compilatorul ca vom folosi acest pachet, priogramul va incepe cu instructiunea :
//Inceput program
import java.io.*;
Limbajul Java permite tratarea erorilor care pot aparea la executia unor instructiuni cum ar fi cele de I/O prin generarea unor exceptii. Intrucat in acest program nu vom face tratarea erorilor de I/O, presupunand ca operatiile de citire vor decurge corect trebuie sa atentionam compilatorul despre acest lucru inhiband astfel generarea exceptiilor. Aceasta se face cu ajutorul clauzei throws din antetul metodei main in care astfel de evenimente se pot produce.
Astfel vom avea:
import java.io.*;
class Maximum
}
Aici am folosit metoda System.out.flush() pentru a forta afisarea. Functiile de afisare inscriu caracterele ce urmeaza sa fie afisate intr-un buffer. In momentul in care bufferul este plin, continutul sau este afisat pe display dupa care este golit pentru a receptiona noi caractere. Metoda flush() forteaza golirea trimiterea spre display a continutului bufferului chiar daca acesta nu este inca plin. De asemenea am folosit pentru afisare metoda System.out.print(). Aceasta metoda, spre deosebire de System.out.println(), efectueaza afisarea fara a trece cursorul pe randul urmator. Pentru citirea datelor de intrare s-a apelat metoda System.in.read() care prea din fisierul standard de intrare un octet reprezentand codul caracterului citit si intoarce valoarea citita. Metoda System.in.skip(1) este apelata pentru a sari peste 1 octet din fisierul standard de intrare si anume peste codul caracterului 'n' (new line) introdus la apasarea tastei ENTER. La afisarea rezultatului, pentru trecerea de la tipul int la char am folosit (char)m aplicand operatorul cast de conversie explicita de tip, cu sintaxa
(<tip>)<operand>
care face conversia operandului la tipul specificat.
Se observa ca in cadrul programului, secventa de instructiuni care realizeaza introducerea datelor:
System.out.print("=");
System.out.flush();
=System.in.read();
System.in.skip(1);
se repeta de trei ori. Putem elimina acest dezavantaj prin definirea unei metode care sa implementeze actiunea de citire a datelor de intrare. Metoda va primi ca parametru String-ul prompt pe care il va afisa ca invitatie adresata utilizatorului de a introduce data, va citi un octet (codul caracterului) si o va returna metodei apelante Metoda va fi definita deci astfel:
int citire(String prompt)
Din motive pe care le vom explica ulterior, pentru a putea fi apelata, aceasta metoda se va declara ca fiind statica. Programul in versiune modulara va fi deci urmatorul:
import java.io.*;
class Maximum
// Metoda principala
public static void main(String[] arguments)
throws IOException
}
Programul va fi editat in fisierul Maximum.java. Comenzile de compilare si executie a programului continut de acest fisier precum si rezultatele afisate sunt redate in figura 5.2.
2. Sa se elaboreze o metoda care sa calculeze si sa intoarca radacina patrata a unui numar. Sa se foloseasca aceasta metoda intr-un program care calculeaza si afiseaza radicalul numerelor de la 1 la 10.
Evident ca metoda cu care calculam manual radicalul nu este aplicabila in cazul calculatoarelor. Vom apela de aceea la un algoritm numeric iterativ bazat pe metoda Newton (numit si metoda tangentei ) de rezolvare a ecuatiilor nelineare.
Fie data ecuatia f(x)=0 unde f(x) este o functie nelineara, continua si derivabila, a carei expresie analitica o cunoastem si avand graficul din figura 5.3.
Solutia ecuatiei f(x)=0 este data de abscisa xS a punctului de intersectie a graficului functiei f(x) cu axa OX. Pentru a gasi pe xS vom aplica urmatorul algoritm:
Alegem pe OX un punc arbitrar de abscisa x0. In punctul de abscisa de pe graficul functiei f(x) ducem tangenta t0(x). Aceasta dreapta tangenta la graficul functiei intersecteaza axa OX in punctul de abscisa x1 (figura 5.4).
Se observa ca valoarea astfel obtinuta este mai aproape de solutia cautata decat (considerand x0 o solutie aproximativa, spunem ca x1 este o aproximatie mai buna a solutiei xS decat x0) . Repetam operatiile dinainte folosind pe x1 in loc de x0 . Obtinem o noua valoare x2 care este o aproximatie si mai buna a solutiei xS decat x1 (figura 5.5).
Repetand in continuare algoritmul se obtine un sir de valori x0, x1, x2, , xk
convergent catre xS cand k tinde spre . Sa incercam acum sa gasim pe baza acestei interpretari geometrice a metodei lui Newton formula recursiva de calcul a valorii la pasul k a solutiei aproximative xk in functie de valoarea xk-1 obtinuta la pasul precedent (k-1). Astfel pornind de la valoarea presupus cunoscuta xk-1 sa gasim ecuatia tangentei tk-1 ( x ) la graficul functiei in punctul de abscisa xk-1. Fiind o dreapta, acesta are ecuatia:
tk-1 ( x )=m xn
Fiind tangenta la graficul lui f(x) in punctul de abscisa xk-1, panta m a tangentei este egala cu derivata functiei f(x) in acel punct. Cunoscand expresia analitica a functiei, putem calcula aceasta valoare:
m = f' (xk-1)
Valoarea parametrului n o putem calcula din conditia de egalitate a valorii functiei f(x)si a tangentei tk-1 ( x ) la graficul functiei in punctul de abscisa xk-1:
tk-1 (xk-1 ) =f' (xk-1 )
adica:
f' (xk-1) xk-1n = f (xk-1 )
Se obtine:
n = f (xk-1 ) - f' (xk-1) xk-1
Deci ecuatia tangentei tk-1 ( x ) in punctul de abscisa xk- la graficul functiei f(x) este:
tk-1 ( x ) = f' (xk-1) x + f (xk-1 ) - f' (xk-1) xk-1
Acum putem gasi relatia dintre xk si xk-1 rezolvand ecuatia tk-1 ( x )= 0, stiind ca solutia acesteia este xk :
f' (xk-1) xk + f (xk-1 ) - f' (xk-1) xk-1= 0
Obtinem astfel formula:
Alegand o valoare initiala arbitrara x0 si aplicand repetat aceasta formula se va obtine sirul de valori x0, x1, x2, , xk convergent catre xS cand k tinde spre . Nu este necesar totusi sa repetam aceste calcule la infinit deoarece precizia de reprezentare a numerelor reale in memoria calculatorului este limitata la un numar finit de cifre zecimale. Ne vom multumi astfel cu o solutie aproximativa xn obtinuta la pasul n care difera de solutia exacta xS printro valoare impusa astfel incat | xS - xn | <
Astfel
daca =
10 -3 atunci solutia gasita are trei zecimale
exacte. Problema este ca nu este
cunoscut, tocmai pe el dorim sa il aproximam. Totusi, daca sirul sirul de valori x0,
x1, x2, , xk este
convergent catre xS cand k tinde spre , atunci si sirul diferentelor converge spre 0 cand k tinde spre . Vom alege drept conditie a opririi a
algoritmului | xk - xk-1 | < In aceste conditii
putem sa trecem la reprezentarea algoritmului gasit printr-o schema logica
(figura 5.6).
Figura 5.6- Schema logica a algoritmului Newton
Sa
partcularizam acum formula generala aalgoritmului la cazul problemei noastre.
Daca x este radacina patrata a numarului
a atunci a = x2 si deci
x poate fi obtinut ca solutie a
ecuatiei x2 - a=0.
Aceasta ecuatie o vom rezolva prin metoda lui Newton prezentata mai sus. Aici f(x)= x2 - a iar f'(x) = 2 x. Obtinem in
aceste conditii relatia recurenta:
Algoritmul il vom implementa in Java folosind structura repetitiva do/while intr-o metoda numita radical. Metoda va primi ca parametru si va intoarce o valoare de tip double. Programul va fi:
class RadicalTestwhile(e >= eps);
return x0;
}
public static void main(String[] arguments)
}
}
Programul
va fi editat in fisierul RadicalTest.java. Comenzile de compilare si executie a
programului continut de acest fisier precum si rezultatele afisate sunt redate
in figura 5.7.
Figura 5.7- Compilarea si executia aplicatiei RadicalTest.java
Pachetele Java API
Asa cum am vazut mai sus, clasele Java API (Applications Programming Interface - interfata de programare a aplicatiilor) sunt grupate in pachete. Un pachet desemneaza un grup de clase interdependente (declarate ca apartinand aceluiasi pachet) plasate intr-un subdirector comun. Pentru a folosi metodele unei clase dintr-un astfel de pachet ele trebuiesc incarcate prin comanda import.
Marele avantaj al limbajului Java este chiar aceasta colectie foarte bogata de clase "prefabricate" ale caror metode, pentru a nu "reinventa roata" pot fi refolosite de programatori in aplicatiile lor. Multe din aceste clase le vom discuta pe parcursul cursurilor urmatoare. In tabelul urmator sunt enumerate pachetele de clase ale Java API cu o scurta descriere a fiecarui pachet:
Pachetul |
Descriere |
java.applet |
Acest pachet contine clasa Applet care defineste un tip special de program Java care poate fi executat de masina virtuala a unui browser intr-o fereastra a acestuia, ca element al unui document HTML. Pachetul mai contine interfetele necesare creerii de programe de tip applet, interactiunii cu browserul si interpretarii de clipuri audio. |
java.awt |
(The Java Abstract Windowing Toolkit). Pachetul contine toate clasele si interfetele necesare creerii si manipularii interfetelor grafice utilizator (GUI - Graphical User Interfaces) |
java.awt.image |
Acest pachet contine clasele si interfetele necesare incarcarii si manipularii imaginilor de catre un program. |
java.awt.peer |
Pachetul contine interfetele necesare interactiunii dintre componentele GUI Java (cum ar fi de exemplu butoanele) cu echivalentii lor dependenti de platforma (de exemplu butoanele gestionate de Windows 95). Java este un limbaj independent de platforma. In aceste conditii, butoanele sunt implementate diferit sub Windows 95 decat sub X Linux . In aceste conditii butonul abstract java va fi afisat si manipulat prin perechea sa dependenta de platforma definita in acest pachet. |
java.io |
(The Java I/O Package) Pachetul Java de Input/Output. Acest pachet ofera clasele necesare programului pentru scrierea/citirea de date in si din fisiere (inclusiv cele standard de intrare, iesire si eroare - consola sistemului). |
java.lng |
(The Java Language Package) - acest pachet este importat automat de compilator in orice program. el contine clasele si interfetele necesare majoritatii programelor Java. |
java.net |
(The Java Networking Package) - contine clasele necesare programelor pentru a comunica intre ele printr-o retea internet (Internet sau Intranet) oferind suportul necesar realizarii de aplicatii client-server. |
java.util |
(TheJava Utilities package) - contine clase care ofera servicii pentru manipularea datei, timpului si generarea/procesarea de valori aleatoare precum si alte utilitati. |
Sumar
In cadrul acestui curs am prezentat aplicarea metodologiei divide et impera pentru proiectarea unor programe modulare.
In limbajul Java modulele de program se prezinta sub forma claselor si metodelor.
La elaborarea unui program Java pot fi folosite metode ale unor clase "prefabricate" din Java API (Applications programming Interface).
Programatorul poate sa creeze propriile sale metode si clase pe care le poate refolosi si in alte programe. Pe parcursul acestui curs s-a prezentat metodologia de proiectare si implementare de catre programator a propriilor metode.
Variabilele declarate in cadrul unei metode se numesc variabile locale.
O metoda poate intoarce ca rezultat o valoare prin executia instructiunii return.
Tipul metodei este dat de tipul valorii intoarse de aceasta.
Daca metoda nu intoarce o valoare, ea se declara de tipul void.
O metoda poate apela la randul sau alte metode.
Terminarea executiei unei metode si revenirea in metoda apelanta se face fie prin executia instructiunii return, fie implicit la executia ultimei instructiuni a metodei.
Variabilele locale si parametrii metodelor nu sunt vizibile din afara acestora.
Clasele "prefabricate" din Java API trebuiesc "importate" pentru a putea fi apelate metodele lor.
Aceste clase sunt organizate pe criterii functionale in "pachete".
A fost prezentata o scurta descriere a pachetele oferite de Java API
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 2669
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved