Sunteți pe pagina 1din 5

Laborator 3

I. DESIGN BY CONTRACT

- reprezinta un "contract" care specifica restrictiile la care trebuie sa se supuna


datele de intrare ale unei metode, valorile posibile de iesire si starile in care se
poate afla programul - aceste restrictii sunt date sub forma unor:
a) preconditii: reprezinta obligatiile pe care datele de intrare ale unei metode
trebuie sa le respecte pentru ca metoda sa functioneze corect
b) postconditii: reprezinta garantiile pe care datele de iesire ale unei metode le
ofera
c) invarianti: reprezinta conditii impuse starilor in care programul se poate afla la
un moment dat
class Treasury{
double amount=0;

void add(double sum){


amount+=sum;
}

double getAmount(){
return amount;
}

boolean payment(double sum){


if(sum<=amount){
amount-=sum;
return true;
}else{
return false;
}
}
}
Treasury:
- invarianti: - amount>=0 si amount diferit de infinit si de NaN
add:
- preconditii: - sum>=0 si amount diferit de infinit si de NaN
getAmount:
- postconditii: - valoarea returnata >=0, si amount diferit de infinit si de NaN
payment:
- preconditii: - sum>=0, si amount diferit de infinit si de NaN

- conditiile de mai sus reprezinta "contractul" pe care clasa Treasury si metodele


ei il ofera si in acelasi timp il necesita de la cei care o folosesc - payment nu are
postconditii fiindca este garantata sa functioneze pentru orice data valida de
intrare, luand toate valorile logice posibile - uneori, pe langa preconditii,
postconditii, invarianti, in contractul unei clase sau al unei metode mai pot aparea
si alte conditii specifice, de exemplu conditii care garanteaza timpii de executie,
scalabilitatea algoritmului in functie de datele de intrare, memoria folosita, etc. In
cazul nostru se poate garanta, de exemplu ca metodele clasei Treasury au
complexitatea O(ct) si ca nu emit niciodata exceptii - specificarea contractului
unei clase sau al unei metode este foarte importanta din mai multe puncte de
vedere:
a) cel care a implementat clasa su metoda restectiva ii spune utilizatorului ce date
sunt considerate valide ca date de intrare. Aceasta il scuteste sa foloseasca teste
de validare a datelor, care in unele cazuri doar ar incetini algoritmul, ele fiind
redundante cu teste care deja sunt facute pentru validarea datelor, de exemplu
imediat ce au fost introduse de catre utilizator. In cazul de mai sus, creatorul
clasei Treasury specifica faptul ca intotdeauna metodele add si payment se
asteapta sa primeasca valori non-negative si atunci nu mai este necesar ca
aceste metode sa implementeze validari de date. Daca utilizatorul foloseste clasa
Treasury cu date incorecte de intrare (sum<0), el nu respecta "contractul" clasei
si atunci rezultatele nu mai sunt garantate ca fiind corecte
b) in acelasi timp utilizatorul stie din contract la ce date posibile de iesire sau stari
intermediare sa se astepte si atunci poate sa-si optimizeze propriul cod in functie
de acestea

- contractul unei clase sau al unei metode se specifica literar, printr-un text, inclus
in program ca un comentariu sau scris in documentatia aferenta - in faza de
dezvoltare a unui program se pot folosi instructiuni care sa testeze indeplinirea
contractului, instructiuni care sa fie scoase pe urma (manual sau automat) din
codul final
void add(double sum)throws Exception{
if(sum<0)throw new Exception("sum is negative");
amount+=sum;
}

- in acest caz metoda raporteaza incalcarea preconditiei prin emiterea unei


exceptii. In faza finala, la predare, acest test se poate comenta sau sterge pentru
a nu ocupa timp procesor si memorie. - Java ofera si un mecanism special pentru
testarea unor conditii in faza de dezvoltare, prin folosirea asertiunilor
void add(double sum){
assert sum>=0:"sum is negative";
amount+=sum;
}
- o asertiune genereaza o exceptie speciala cu textul dat dupa ":", in cazul in care
conditia ei este falsa. Deoarece asertiunile au fost introduse mai tarziu in limbajul
Java trebuie specificat la optiunile de compilare: -source 1.4 - implicit asertiunile
nu fac nimic (sunt dezactivate), ca si cum codul este pregatit pentru livrare. Daca
dorim sa activam asertiunile trebuie sa specificam la optiuni: -enableassertions
(sau -ea)

II. LISKOV SUBSTITUTION PRINCIPLE (LSP)


abstract class Computer{
abstract String getOpticUnitType();
}

class Desktop extends Computer{


String opticUnitType;
...
String getOpticUnitType(){
return opticUnitType;
}
}

class Tablet extends Computer{


String getOpticUnitType()throws Exception{
throw new Exception("No unit");
}
}

- concluzia este ca intr-o superclasa nu putem avea definite decat acele


proprietati care sunt intr-adevar valabile pentru toate subclasele ei si care au un
comportament unitar - cea mai simpla metoda de a verifica acest principiu este sa
testam in orice secventa de cod in care se foloseste o anumita clasa derivata din
superclasa, ca acea clasa se poate substitui cu orice alta clasa derivata din
aceeasi superclasa - LSP spune exact acest lucru:
! mostenirea trebuie sa asigure faptul ca orice proprietate valabila pentru
superclasa, de asemenea se mentine pentru oricare din subclasele ei

- acest principiu spune ca relatia de baza care exista intre o subclasa si


superclasa ei, si anume "IS A", trebuie inteleasa si intr-un sens comportamental
("behavior") si nu doar unul structural ("structure") - un alt corolar al acestui
principiu, folosit in conjunctie cu design by contract, este urmatorul:
! cand se redefineste o metoda intr-o clasa derivata, preconditiile ei se pot
inlocui doar cu unele mai slabe, iar postconditiile ei, doar cu unele mai
puternice
abstract class S{
//preconditii: n1,n2 - numere pozitive
//postconditii: rezultatul este numar pozitiv
abstract f(int n1,int n2);
}

class D1 extends S{
//preconditii: n1,n2 - orice numere
//postconditii: rezultatul este numar pozitiv par
int f(int n1,int n2){...}
}

class D2 extends S{
//preconditii: n1,n2-numere pozitive
//postconditii: rezultatul este orice numar
int f(int n1,int n2){...}
}

- clasa D1 respecta LSP fiindca la implementarea functiei f preconditiile sunt mai


slabe decat cele din contractul superclasei S, ceea ce garanteaza ca orice set de
date valabil pentru S va fi valabil si pentru D1, si in acelasi timp postconditiile lui f
din D1 sunt mai tari decat cele cerute in S, ceea ce garanteaza ca orice rezultat
pe care f din D1 il returneaza este o submultime valida a rezultatelor pe care prin
contract f din S trebuie sa le garanteze - D2 nu respecta LSP fiindca
implementarea lui f din D2 are postconditii mai slabe decat cele cerute in S si
atunci pot sa rezulte cazuri in care folosirea unei instante a lui D2, desi este
corecta in sine conform propriului contract, nu respecta contractul contextului
general din care ea face parte (contractul lui S) - un alt aspect important cerut de
LSP este ca in clasele derivate nu putem implementa o metoda din superclasa ca
avand functionalitate nula (NOP-no operation). De exemplu ar fi incorect in clasa
Tablet sa implementam functia getOpticUnitType la modul:
String getOpticUnitType(){
return null;
}

- revenind la exemplul initial, o implementare corecta ar fi una in care metoda


getOpticunitType ori sa fie implementata intr-un layer separat de abstractizare,
sau sa fie declarata intr-o interfata care sa fie implementata doar acolo unde este
nevoie de ea:
abstract class Computer{}

interface OpticUnit{
String getOpticUnitType();
}

class Desktop extends Computer implements OpticUnit{


String getOpticUnitType(){...}
}
class Tablet extends Computer{}

III. TEMA

1. Se cere un scurt program de test (main), diagrama UML si contractele pentru


clasele (incluzand implementarea metodelor lor), care indeplinesc urmatoarele
conditii: - se doreste calculul derivatei pentru mai multe tipuri de functii:
polinomiala (cnxn+cn-1xn-1+...+c1x+c0), exponentiala(cx), logaritmica(logcx). - functia
care calculeaza derivata va avea forma: double[] derivata(double[] a); unde a este
un array care contine toate constantele necesare functiei de derivat (de la stanga
la dreapta), si returneaza un alt array cu constantele functiei derivate - functia
derivata() este definita intr-o clasa abstracta Functie din care se vor deriva clase
specifice fiecarui tip de functie

2. Se cere un scurt program de test (main), diagrama UML si contractele pentru


clasele (incluzand implementarea metodelor lor), care indeplinesc urmatoarele
conditii: - se doreste calculul unghiului de refractie al unei raze de lumina cu o
functie de forma double unghiRefractie(double u i,double ce); unde ui este unghiul
de intrare al razei de lumina, iar ce este constanta de refractie a mediului exterior
- functia va returna unghiul razei in mediul interior definit in clasa, iar daca se iese
din domeniul unghiurilor de refractie, se returneaza infinit. - avem 3 tipuri de
corpuri: solid, lichid si gazos - la corpurile gazoase indicele de refractie variaza
direct proportional dupa o constanta data cu compresia acelui gaz:
ci=compresie*ci0 - ci este constanta interna de refractie a mediului respectiv -
compresie este gradul de compresie - ci0 este constanta interna de refractie a
mediului pentru grad de compresie 1 - unele corpuri solide sunt opace si pentru
acestea nu exista refractie - clasa de baza se numeste Corp
Page last modified on November 02, 2010, at 09:42 AM
 ▲ Top ▲
 Search
 Recent Changes

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