rss
    System.out.println("Hello World");

joi, 25 noiembrie 2010

Constrangeri, procese si specificatii in java: Partea IV Specificatii - constructia dupa plan a obiectelor

Uau! Put your hands in the air!
Suntem din nou aici cu specificatiile si cu toate lucrurile fascinante pe care ele ni le ofera!
Vreau sa va aud America, toti impreuna…
….

Ups! Stai ca scriem in romana… Hai frate...
....
E asta e!

Prezentam datile trecute cerintele pentru care ne luptam cu aceste specificatii.
Printre altele, este visul meu de la 3 ani (de cand mama ma obliga sa invat Luceafarul pe dinafara),
Sa pot construe obiecte in mod dynamic.
Mai précis, habar nu am la momentul rularii ce si cum trebuie sa arate un obiect, dar stiu ca am datele si regulile pe care acest obiect trebuie sa le indeplineasca, undeva, intr-un fisier, intr-o baza de date.
Pot specificatiile sa ma ajute in aest caz?
Ei bine nu, dar o pot face intr-un caz intermediar.
Dar daca dezvoltam putin conceptul de specificatie, vom obtine si acest comportament pur dinamic.
(intr-o postare ulterioara, poate il dezvoltam).

Despre constructia dupa plan a unui obiect!



Cand ne cumparam un nou televizor, ne uitam dupa anumite caracteristici.
Vreau ca televizorul sa aiba contrast cel putin 30000:1, sa aiba o diagonala de cel putin 66 cm, sa fie capabil sa decodeze si dvb-t si dvb-c, sa aiba gauri de conectare pentru cat mai multe tipuri de mufe, iar in final sa nu coste mai mult de 1300 ron.
O companie producatoare, poate lua aceste specificatii si imi poate livra mai multe sortimente de televizoare din gama lor care respecta aceste caracteristici.
Mai mult, companii competitoare, pot oferi produse conforme cu aceste specificatii.
Cuvantul cheie aici pare a fi „specificatii”.

La fel se intimpla si in viata computerelor.
Cand inserati o poza intr-un procesor de texte, textul curge pe langa poza.
Voi ati specificat locatia pozei si poate modul in care textul sa curga pe langa poza.
Din aceste specificatii, procesorul de texte va aranja liniile si cuvintele de asa natura incat sa se conformeze.
Desi nu e chiar vizibil la inceput, acest concept de specificatii, este fix acela pe care l-am folosit la validare si la selectie.
Desi implementarea va diferi putin, deoarece de data asta, nu e un filtru pentru obiecte existente, nu e un test pentru obiecte pentru a le testa integritatea, ci este o modalitate de a construi obiecte inexistente si de a le configura.

Multi dintre voi veti spune:
Bine, bine, de ce nu pot face o clasa, in care sa fac tot felul de metode, care sa constituie pasii constructiei?
Asa ar arata un generator de obiecte scris fara specificatii. Metodele respective ar defini comportamentul generatorului.

Insa, daca definim o interfata pentru generator, bazat pe specificatii, atunci aceasta ar constrange in mod explicit produsul generatorului, sa fie conform cu acea specificatie.
Aceasta abordare are cateva avantaje:
- Interfata generatorului este detasata de implementarea sa. Ea defineste, declara, ce lucruri vor trebui respectate, facute, fara a impune si cum aceste lucruri vor fi facute, lasand asta la latitudinea generatorului
- Interfata ofera posibilitatea ca programatorii sa inteleaga ce sa se astepte de la generator, fara ca acestia sa fie nevoiti sa inteleaga cum lucreaza generatorul de fapt. Singurele modalitati de a intelege rezultatele unui generator scris de o maniera procedurala, e prin rularea de diverse cazuri de test, ori prin intelegerea orcarei linii de cod.
- Interfata este mult mai flexibila, sau poate fi imbunatatita mult mai flexibil, deoarece documentul de cerinte este in mana clientilor (ei hotarasc cum si in ce fel va functiona softul), pe cand generatorul nu va trebui decat sa tina seama, sa respecte aceste specificatii.
- Aceasta interfata este mai usor de folosit si la testare, deoarece declara in mod explicit ce „input” trebuie dat generatorului, precum si un mod de a testa ceea ce iese din generator. Asa cum aminteam mai sus, specificatiile acestea pot fi folosite si in rolul lor de validare (daca implementarea o suporta (pentru asta se foloseste paternul assert despre care vom vorbi intr-o postare ulterioara)).


Dar unde este java?

Of, m-ati omorat cu aceasta intrebare! Vine, vine si java, e pe drum, i-auziti,
teleap-teleap!

Sa luam un exemplu al celor de mai sus. Nimic nu ne serveste mai concret decat un exemplu pedagogic.
Am fi putut scoate din programele noastre un exemplu, dar exemplele din viata reala tind sa fie mult prea complexe si cu detalii de implementare care omoara conceptul de baza.
Si de data aceasta, pentru a exemplifica ceea ce vrem sa spunem, Fovler si cu Evens ne sunt de mare ajutor.

Vom folosi exemplul oferit de Evens, in cartea sa.
Folosim aest exemplu, deoarece el ne-a ajutat si pe noi, in aplicatia noastra de facturi, comenzi si livrari.
Desi noi acolo vorbeam de alimente si bunuri de larg consum, nu de chimicale cum ne arata Evens in continuare.
Am folosit doar codul din acest exemplu, restul de comentarii, expliatii sunt ale noastre (adica ale mele, ce tot vorbesc eu asa la plural! Anunturicl dormi?)

Deci avem un program, care trebuie sa impacheteze cateva chimicale inofensive, dar foarte pretentioase la un loc.
Avem tnt care e explozibil, avem Amonium care e volatil, avem probe biologice (cum ar fi nisipu).
Si de parca nu ar fi de ajuns, mai exista si reguli care privesc combinatia dintre toate acestea.
Pe scurt regulile sunt asa:
Tnt nu poate sta decat in Container Blindat.
Amoniu nu poate sta decat in container ventilat.
Nisipu poate sta oriunde, dar nu poate fi in acelas container cu tnt-ul.

Vom scrie deci clase de specificatii pentru container.
Acestei specificatii de container, ii vom furniza caracteristicile de container.
Fiecare chimicala va avea o specificatie de container, configurata cu niste caracteristici de container.
Deci vom avea clasele: ContainerSpecification, ContainerFeature, precum si clasa Drum (chimicala).
Clasa ContainerSpecification va contine o caracteristica de container pe care containerul trebuie sa o indeplineasca.
Pentru a verifica acest lucru (dupa cum va amintiti de la validare) scriem o metoda.
Clasa va arata asa:

public class ContainerSpecification {
private ContainerFeature requiredFeature;
public ContainerSpecification(ContainerFeature required) {
requiredFeature = required;
}

boolean isSatisfiedBy(Container aContainer){
return aContainer.getFeatures().contains(requiredFeature);
}
}

Uitati cum vom construi specificatia unei chimicale:

tnt.setContainerSpecification(
new ContainerSpecification(ARMORED));

Am zis ca intr-un container sunt mai multe chimicale.
Va trebui deci sa il putem intreba pe container daca este impachetat in siguranta.
El va realiza acest lucru, intreband toate chimicalele din interiorul sau, daca el le satisface specificatia de container.
Cu alte cuvinte, cum un baiat intreaba o fata (sunt bun la pat iubit-o)?

Iata metoda din container care verifica acest lucru:

boolean isSafelyPacked(){
Iterator it = contents.iterator();
while (it.hasNext()) {
Drum drum = (Drum) it.next();
if (!drum.containerSpecification().isSatisfiedBy(this))
return false;
}
return true;
}


In acest moment am putea scrie foarte usor o bucata de cod care sa preia toate posibilitatile din baza de date sis a le verifice daca sunt bine ambulate:
Iterator it = containers.iterator();
while (it.hasNext()) {
Container container = (Container) it.next();
if (!container.isSafelyPacked())
unsafeContainers.add(container);
}

Dar nu pentru asta am fost platiti. Puteti sa le spuneti clientilor vostri ca, datorita inteligentei voastre, informatiilor gasite pe acest blog si cu bunavointa lui Fovler si Evens, puteti, folosind domain driven design, sa scrieti usor orice noua cerinta, dar noi vroiam sa generam obiecte.
Am vazut insa, cat de usor e sa implementezi si partea de validare daca doresti.

Revenim la cazul nostrum, trebuie sa scriem un soft, care preia niste chimicale, niste containere si optimizeaza impachetarea acestora.
Vom scrie o interfata pentru un serviciu care sa faca asta.
Pentru ca mai intai ne-am lamurit cum e cu partea de test a impachetarii, acum ne va fi foarte usor sa facem asta:

public interface WarehousePacker {
public void pack(Collection containersToFill,
Collection drumsToPack) throws NoAnswerFoundException;

/* Cerinta: La finalul metodei pack(), ContainerSpecification
Al fiecarui Drum trebuie sa fie satisfacuta de al sau Container.
Daca o solutie completa nu poate fi gasita, se va arunca o exceptie */

}

In acest moment, implementarea modului de impachetare a fost detasata de restul design-ului, ne incarcandu-l pe acesta.
Dar atentie, regulile care definesc domeniul de activitate, au ramas incluse in modelul de proiectare.

Vom vorbi putin aici si de lucrul in echipa.
Adesea se intimpla ca echipe de programatori sa lucreze la portiuni de aplicatii in parallel, dar acele portiuni de aplicatii sa fie interdependente, astfel incat, la un moment dat, in cazul unui design prost, una, sau mai rau, ambele echipe vor stagna.
Sa luam acest exemplu.
A scrie un soft de optimiare, de orice fel ar fi el, este o provocare mareata, desigur daca vorbim de un optimizator pe bune sin u unul cu numele.
Inchipuitiva ca avem o echipa incercand sa dezvolte serviciul de impachetare, iar alta echipa incercand
Sa scrie restul de cod.
Cea de a doua echipa, va scrie codul de integrare in baza de date, scoaterea de date de acolo, introducerea lor in serviciul de impachetare, preluarea rezultatelor de la acesta, interpretarea si afisarea lor.
Ce ne facem insa, ca ei nu pot face decat oleaca de integrare cu baza de date, pot eventual sa faca designul la o interfata grafica, dar cam atit.
Nici macar nu pot sa arate un prototip utilizatorilor sis a aiba un feetback (aferentatie inversa in romana! Eeee! Va place ce cuvinte stiu?), de la ei despre functionarea softului,
Deoarece acest feetback nu ar fi valabil decat in cazul unui system functional de la cap la coada.
Dar stati putin, ca cu design-ul prezentat mai sus, aceasta a doua echipa, poate scrie repede un optimizator nu tocmai performant, dar sufficient pentru a prezenta softul clientilor, iar la momentul cand prima echipa a terminat marele optimizator performant, acesta doar sa fie introdus in soft.
Cum arata codul echipei a doua deci:

public class Container {
private double capacity;
private Set contents; //Drums

public boolean hasSpaceFor(Drum aDrum) {
return remainingSpace() >= aDrum.getSize();
}

public double remainingSpace() {
double totalContentSize = 0.0;
Iterator it = contents.iterator();
while (it.hasNext()) {
Drum aDrum = (Drum) it.next();
totalContentSize = totalContentSize + aDrum.getSize();
}
return capacity – totalContentSize;
}

public boolean canAccommodate(Drum aDrum) {
return hasSpaceFor(aDrum) &&
aDrum.getContainerSpecification().isSatisfiedBy(this);
}

}


public class PrototypePacker implements WarehousePacker {

public void pack(Collection containers, Collection drums)
throws NoAnswerFoundException {

/* Aceasta metoda satisface cerinta asa cum a fost ea scrisa in interfata. Totusi, cand are loc o exceptie, este posibil ca datele continute in containere sa se fi schimbat. Activitatea de rollback trebuie realizata la un nivel mai sus. */

Iterator it = drums.iterator();
while (it.hasNext()) {
Drum drum = (Drum) it.next();
Container container =
findContainerFor(containers, drum);
container.add(drum);
}
}
public Container findContainerFor(
Collection containers, Drum drum)
throws NoAnswerFoundException {
Iterator it = containers.iterator();
while (it.hasNext()) {
Container container = (Container) it.next();
if (container.canAccommodate(drum))
return container;
}
throw new NoAnswerFoundException();
}

}

Si cu aceasta am exemplificat si a treia caracteristica a specificatiilor. Lucrurile pot fi dezvoltate de aici mult mai mult, dar asta depinde si de timpul si de bugetul si de cheful pe care il aveti.
Aveti insa, prin amabilitatea ;lui Evens si Fovler si din experienta noastra cu acest concept, o modalitate corecta si completa de a modela anumite lucruri, astfel incat san u mai injurati ori de cate ori un client va cere un lucru nou.
Dupa cum s-a vazut intr-un soft bine modelat, lucrurile chiar grele se adauga relative usor.
Va multumesc ca ati urmarit acest serial de 4 zile, iar maine va invite la un vot pe care AnunturiCL il va realize.
In functie de dorinta dumneavoastra,
Vorbim despre un subiect sau altul, sau nu mai vorbim de loc!
Multumiri avem si pentru:
Fovler si Evens pentru munca depusa in domeniul software developing, pentru ca ne-au scos pe noi la momentul potrivit din rahat cu gandirea lor extraordinara si ca au pus la dispozitia lumii intregi, cunostintele lor.


In elaborarea acestui articol ne-am sprijinit pe:

Domain-driven design : tackling complexity in the heart of software / Eric
Evans.
p. cm.
Includes bibliographical references and index.
ISBN 0-321-12521-5

Evans, E., and M. Fowler. 1997. "Specifications." Proceedings of PLoP 97 Conference.

miercuri, 24 noiembrie 2010

Constrangeri, procese si specificatii in java: Partea III Specificatii - Selectia

Atacam astazi a doua cerinta pentru specificatii, selectia cu toate problemele sale.


Despre selectie!

Aici avem doua sub probleme.
Le vom ataca pe rand.
Pentru simplitate vom presupune mai intai ca toate datele le avem in memorie si ca nu avem nevoie de date din baza de date.
Ne referim la acelas exemplu cu facturile.
Vrem sa obtinem toate facturile „delicvente”:


public Set selectSatisfying(InvoiceSpecification spec) {

Set results = new HashSet();
Iterator it = invoices.iterator();
while (it.hasNext()) {
Invoice candidate = (Invoice) it.next();
if (spec.isSatisfiedBy(candidate)) results.add(candidate);
}

return results;
}

Sa zicem ca aceasta metoda se afla in repository de facturi (InvoiceRepository).
Un client va putea obtine deci toate aceste facturi, bazandu-se pe o specificatie:

Set delinquentInvoices = invoiceRepository.selectSatisfying(
new DelinquentInvoiceSpecification(currentDate));

Din pacate, este foarte rar cazul cand avem toate datele in memorie, iar interactiunea cu baza de date, desi pare simpla pentru unii, este cel mai greu de obtinut in conditii corecte.
Este cu atit mai greu cu cat, ne dorim obtinerea unui model detasabil fata de baza de date si in care interogarile sql san u apara la fiecare pas.
Vom prezenta in continuare, pasi prin care am trecut cu rationamentul pentru a ajunge la codul perfect.
In continuare, de ajutor ne-au fost (prin scrierile lor Fovler si Evens).
Mai intai, ca multi dintre voi, ne-am gandit sa bagam in clasa specificatie o metoda ca urmatoarea:

public String asSQL() {
return
"SELECT * FROM INVOICE, CUSTOMER" +
" WHERE INVOICE.CUST_ID = CUSTOMER.ID" +
" AND INVOICE.DUE_DATE + CUSTOMER.GRACE_PERIOD" +
" < " + SQLUtility.dateAsSQL(currentDate);
}

Cum ziceam, acest lucru implica insa o problema, o sa incepem sa avem cod sql peste tot in aplicatie si asta nu ar fi asa o problema, daca nu ar depinde acest sql de structura tabelelor din baza de date.
Regula generala:
Informatia despre baza de date si structura ei, trebuie bine izolata intr-un strat (layer) de legatura intre aplicatie si baza de date sin u trebuie sa iasa de acolo.
Altfel, vom avea probleme de intretinere a aplicatiei.
S
Solutia numarul doi, este sa urmam regula de mai sus, vom pune interogarea in InvoiceRepository, formand o Metoda de interogare specializata, darn u vom furniza toate detaliile reguli de verificat, pentru a nu introduce detalii despre aplicatie in stratul (layer) legat de baza de date.
Ci vom divide funtionalitatea intre cele doua straturi si vom folosi un mechanism de chemare dubla (double dispatch) pentru a realize verificarea regulii.
(despre patterni de dispatch si dispatchers, vom vorbi intr-o alta postare).

public class InvoiceRepository {

public Set selectWhereGracePeriodPast(Date aDate){
String sql = whereGracePeriodPast_SQL(aDate);
ResultSet queryResultSet =
SQLDatabaseInterface.instance().executeQuery(sql);
return buildInvoicesFromResultSet(queryResultSet);
}

public String whereGracePeriodPast_SQL(Date aDate) {
return
"SELECT * FROM INVOICE, CUSTOMER" +
" WHERE INVOICE.CUST_ID = CUSTOMER.ID" +
" AND INVOICE.DUE_DATE + CUSTOMER.GRACE_PERIOD" +
" < " + SQLUtility.dateAsSQL(aDate);
}

public Set selectSatisfying(InvoiceSpecification spec) {
return spec.satisfyingElementsFrom(this);
}
}

public class DelinquentInvoiceSpecification {

public Set satisfyingElementsFrom(
InvoiceRepository repository) {
return repository.selectWhereGracePeriodPast(currentDate);
}
}

Aceasta varianta, aseaza interogarea in repository, in timp ce specificatia controleaza ce interogare va fi folosita.
Chiar daca regula nu e toata in specificatie, essential este ca in specificatie se defineste clar ce inseamna “delicventa” unei facturi si anume depasirea perioadei de gratie.

Repository are acum o metoda de interogare foarte specializata, care probabil va fi folosita doar in cazul “delicventei”.
Asta este acceptabil, dar gandindu-ne la numarul de facturi care doar au deposit perioada de scadenta, fata de cele “delicvente”, ajungem la o solutie intermediara, care face metodele din repository mai generale, lasand specificatia sa fie mai concreta.

public class InvoiceRepository {

public Set selectWhereDueDateIsBefore(Date aDate) {
String sql = whereDueDateIsBefore_SQL(aDate);
ResultSet queryResultSet =
SQLDatabaseInterface.instance().executeQuery(sql);
return buildInvoicesFromResultSet(queryResultSet);
}

public String whereDueDateIsBefore_SQL(Date aDate) {
return
"SELECT * FROM INVOICE" +
" WHERE INVOICE.DUE_DATE" +
" < " + SQLUtility.dateAsSQL(aDate);
}

public Set selectSatisfying(InvoiceSpecification spec) {
return spec.satisfyingElementsFrom(this);
}
}

public class DelinquentInvoiceSpecification {
//alt cod.

public Set satisfyingElementsFrom(
InvoiceRepository repository) {
Collection pastDueInvoices =
repository.selectWhereDueDateIsBefore(currentDate);

Set delinquentInvoices = new HashSet();
Iterator it = pastDueInvoices.iterator();
while (it.hasNext()) {
Invoice anInvoice = (Invoice) it.next();
if (this.isSatisfiedBy(anInvoice))
delinquentInvoices.add(anInvoice);
}
return delinquentInvoices;
}
}


In speranta ca sunteti multumiti de cat java ati vazut, chit ca discutam incontinuare despre business layer, va spun ca urmeaza cea mai interesanta parte,
Aceea a constructiei obiectelor dupa un plan bine stabilit, intr-un mod declarativ, fara prea multe if-uri thenuri.
Practic urmeaza un generator de obiecte pe care il voi prezenta.
Deci nu pierdeti episodul de maine!

Va urma

In elaborarea acestui articol ne-am sprijinit pe:

Domain-driven design : tackling complexity in the heart of software / Eric
Evans.
p. cm.
Includes bibliographical references and index.
ISBN 0-321-12521-5

Evans, E., and M. Fowler. 1997. "Specifications." Proceedings of PLoP 97 Conference.

marți, 23 noiembrie 2010

Constrangeri, procese si specificatii in java: Partea II Specificatii - Validarea

Ati vazut ce nume de site are bunul meu prieten?
Inchipuitiva prin ce calvar trebuie sa trec cand strig dupa el pe strada:
„bai anunturicl, ba anunturicl, stai dracu sa ne luam si noi o saorma”!

Aveti deci mai jos, prin bunavointa gazdei noastre, o aplicatie exemplu, cei dintre voi care doriti sa aveti ceva asemanator, dar mai evoluat, puteti sa ne contactati si vom fi mai mult decat bucurosi sa adaugam aplicatiei cerintele voastre.

Revenim la continuarea serialului nostru despre subiectele incepute ieri!

prezentam postarea trecuta, constrangerile si procesele si va promiteam ca vom reveni cu un model, cu un patern, care sa rezolve aceasta problema a constrangerilor si a proceselor.
Trecand prin tot procesul anterior prezentat, am ajuns noi la concluzia ca ne-ar trebui un concept de modelare care sa ne permita urmatoarele:
- Validarea: O modalitate prin care sa pot verifica constrangerile, sau anumite caracteristici importante;
- Selectia: Fiind date mai multe obiecte de acelas tip, ma intereseaza sa le obtin pe acelea care respecta constrangerea/regula, sau din potriva, sa le aleg pe acelea care nu respecta constrangerea/regula;
- Constructia: As dori sa pot construi un obiect, dupa niste reguli date si regulile respective sa fie verificabile. Mai precis as dori sa pot construi un obiect dupa un plan dat, adica, spre exemplu, la o masina stiu ca trebuie sa ii pun mai intai motorul si apoi caroseria, sau invers. Sa am un numar de pasi dupa care sa ma ghidez in constructia unui obiect.
Mai mult, constructia unui obiect se poate realiza in diferite conditii:
Obiectul abia a fost creat, deci e un obiect nou;
Obiectul se afla in baza de date, deci el trebuie luat de acolo si adus in aplicatie;
Alte cazuri.
Daca s-ar putea, am zis noi, ar fi chiar tare daca acest concept de modelare ne-ar oferi si posibilitatea de a combina aceste constrangeri intr-un lant de constrangeri aplicate.
Un cuvant ne-a venit la amindoi in minte:
- Frate, asta suna ca si cum ai construi specificatia unui produs;

Am inceput sa cautam febril daca exista un astfel de concept de modelare.
Si l-am gasit intr-un articol de Evans si Fovler din anul 1997, dar si mai tarziu intr-o carte a lui Evens.

Ne intoarcem putin la exemplul cu facturi.
Cum am aratat mai sus, avem tendinta de a testa cu metode booleene toate constrangerile care ne apar pe un obiect.
Acest lucru merge perfect atita timp cat regulile sunt simple.
Deci la o clasa pentru factura, verificarea faptului ca o factura a depasit data scadenta ar fi:

public boolean isOverdue() {
Date currentDate = new Date();
return currentDate.after(dueDate);
}

Ce ne facem insa daca vrem sa verificam ca o factura este „delicventa” adica a depasit orice urma de bun simt.
Pentru aceasta, verificarea ar incepe mai intai cu constrangerea faptului ca factura trebuie sa fi depasit data scadenta.
Dar, mai departe trebuie sa ne bazam verificarea pe un plan de gratiere (acea perioada de gratie acordata la o factura), plan de gratiere care poate fi diferit de la client la client, in functie de statusul contului clientului respectiv, de ofertele pe care clientul le poate primi si de comportamentul financiar si nu numai al clientului.
Mai mult, e vorba si de procesul de dupa (vedeti, ajungem iar la procese).
Unele facturi pot fi gata pentru un al doilea avertisment care sa fie trimis clientului, pe cand altele abia se afla la primul avertisment, sau mai rau, sunt gata de a fi trimise la recuperatori.
Este clar ca, functionalitatea de baza a unei facturi, aceea de a fi un document de cerere de plata, se va pierde printre tonele de cod de verificare de reguli.
Clasa factura va dezvolta de asemenea o multime de dependente fata de alte clase, care la baza, nu aveau treaba cu acest concept.
Acum, multi dintre voi, ati lua acest cod de verificare al regulilor si l-ati pune in partea de prezentare a aplicatiei.
Ati lua factura asa cum e ea din baza de date, ati aduce-o in cod si de acolo abia la prezentarea ei sau la salvarea ei ati verifica datele.
Din pacate, acest comportament, lasa in urma un obiect cu date mort, care nu stie sa se verifice singur pentru regulile elementare din domeniu specific.
Verificarea regulilor si a constrangerilor, trebuie sa ramana in modelarea domeniului specific (ceea ce se cheama in design business layer), dar daca nu se potriveste in cadrul definitiei unui obiect, cum ar fi factura, modelati-l ca obiect separat.
Nu doar atit, dar evaluarea regulilor cu metode conditionale, va face regulile sa fie greu de citit.
Dezvoltatorii care lucreaza cu paradigma programarii logice, ar scapa usor.
Ei ar construi predicate pentru fiecare regula si ar evalua factura cu aceste predicate.
Predicatele sunt functii care returneaza adevarat sau fals bazat pe o anumita regula.
Acestea, predicatele, pot fi combinate folosind operatori logici cum ar fi conjunctia si disjunctia.
Numai ca noi, avem o mica problema, una mica de tot, aproape de detaliu as putea spune.
Nu suntem in paradigma de programare logica.
Din fericire, nici nu ne trebuie intreaga paradigma logica de programare, ci avem nevoie doar de conceptul de predicat.
Vom modela acest concept de predicat prin obiecte separate, de sine statatoare, care pot primi si evalua starea unui alt obiect.
Informatiile de care acest predicat are nevoie, ii vor fi date la creiere de catre un factory.
In acest fel, obiectul factura isi va pastra functionalitatea sa de baza.
Vom lua pe rand cele trei cerinte ale noastre de mai sus, prezentandu-le pe rand in cate o postare, astazi validarea:

Despre validare!

Ne intoarcem la exemplul cu factura, sa o verificam daca este” delicventa”...

class DelinquentInvoiceSpecification extends
InvoiceSpecification {
private Date currentDate;
//o instanta este utilizata si apoi distrusa intr-o singura zi

public DelinquentInvoiceSpecification(Date currentDate) {
this.currentDate = currentDate;
}

public boolean isSatisfiedBy(Invoice candidate) {
int gracePeriod =
candidate.customer().getPaymentGracePeriod();
Date firmDeadline =
DateUtility.addDaysToDate(candidate.dueDate(),
gracePeriod);
return currentDate.after(firmDeadline);
}

}

Pentru a vedea cum sa utilizam aceasta clasa/specificatie, presupunem acum ca va trebui sa aratam in aplicatie un semn distinctiv ori de cate ori un vanzator aduce persoane rau platnice.

Codul ar arata cam asa:

public boolean accountIsDelinquent(Customer customer) {
Date today = new Date();
Specification delinquentSpec =
new DelinquentInvoiceSpecification(today);
Iterator it = customer.getInvoices().iterator();
while (it.hasNext()) {
Invoice candidate = (Invoice) it.next();
if (delinquentSpec.isSatisfiedBy(candidate)) return true;
}
return false;
}


In felul acesta, regulile de verificare ale unei facturi, sunt in propriul lor obiect, iar factura isi vede linistita de functionalitatea ei.


Va urma


In elaborarea acestui articol ne-am sprijinit pe:

Domain-driven design : tackling complexity in the heart of software / Eric
Evans.
p. cm.
Includes bibliographical references and index.
ISBN 0-321-12521-5

Evans, E., and M. Fowler. 1997. "Specifications." Proceedings of PLoP 97 Conference.

luni, 22 noiembrie 2010

Prima aplicatie gratuita in Java

Buna seara.
Voi prezenta in continuare o aplicatie de pontaj electronic, aplicatie conceputa binenteles in Java.
Dupa cum bunul meu prieten black ares v-a expus in posturile anterioare, pe acest blog, veti gasi si aplicatii practice care sa puna in lumina teoria prezentatata de noi despre Java.

Pontaj electronic.

Ideea este simpla, dorim sa tinem intr-o baza de date evidenta zilelor lucrate ale angajatilor unei firme. Aplicatia poate fi extinsa si i se poate adauga un modul de conectare la un cititor de carduri de proximitate si preluarea orelor de intrare si respectiv de iesire direct de la cititor.

Aplicatia prezentata este destul de simpla : baza de date utilizata este derby, pentru generarea fisierului .xls s-a folosit libraria jxl, iar pentru realizarea Helpului am folosit HelpMaster un soft free care mie personal mi-a placut foarte mult.

Atasez un link cu aplicatia finala si astept intrebari si eventuale comentarii.

Aplicatia poate fi descarcata de la Pontaj Electronic in Java

Click pe linkul din josul paginii.

Succes.

Constrangeri, procese si specificatii in java: Partea I Constrangeri si procese

Salutare extinsa tuturor!

Inainte de a incepe postarea de azi, va atrag atentia asupra unui fapt. Ati observat pe parcursul postarilor anterioare, diverse subiecte despre care spunem ca vom vorbi in postari ulterioare.
Ei bine, publicam pe moment ce ne intilnim cu ele si va facem prezentarea unui caz concret.
Insa, daca vreunul dintre voi doreste tratarea unuia din subiectele enumerate, sau a altui subiect, nu are decat sa comenteze si vom extrage din experienta noastra episoade importante despre subiectul respectiv.

Revenim la postarea de azi.
Lucram impreuna cu prietenul meu si gazda noastra pe acest blog la un program cand am fost loviti de o revelatie:
- Bai, tu vezi cate if-uri sunt prin bucatile astea de cod?
- Da ma, chiar ma gindeam sa vad cum naiba sa le rescriem sa nu mai fie atitea, sau ma rog, sa nu mai aiba atita cod.

Care e problema?

Problema este ca adesea ne intilnim cu situatii in care trebuie sa ne asiguram ca o anumita caracteristica a unui obiect este respectata, drept pentru care trebuie sa o controlam mereu sa vedem respectarea ei. In Object Oriented Programming asta se cheama realizarea de invarianti asupra unui produs si impunerea de constrangeri.
Deci unul din subiectele despre care vom vorbi azi sunt constrangerile. Nu plecati, nu e singurul!
Invariantul este o caracteristica a unui obiect care nu se poate schimba. Constrangerea este regula impusa ca invariantul sa fie respectat.

Unde v-ati intalnit cu astea?

Foarte des, dar mai precis intr-un soft de comenzi si facturi pe care il dezvoltam impreuna, de aceea exemplele vor fi din acest soft.
Vom vedea acum un caz simplu. Sa presupunem ca aplicatia noastra realizeaza si impachetarea marfii.
Avem un container cu 100 kg capacitate. Deci asta, 100 kg, e o caracteristica care nu poate fi schimbata, atita poate containerul.
Ajungem la concluzia ca pentru container capacitatea este un invariant si ca genereaza o constrangere.
Asta inseamna ca in fiecare metoda care are de a face cu capacitatea, trebuie sa ne asiguram ca nu depasim respectiva capacitate.
Multi dintre voi ar face asa:

class Container {
private float capacity;
private float contents;

public void pourIn(float addedVolume) {
if (contents + addedVolume > capacity) {
contents = capacity;
} else {
contents = contents + addedVolume;
}
}
}

Cazul de fata este unul simplu, dar ganditi-va ce ar fi daca metodele acestui obiect ar fi mai complexe si mai multe.
Ce va faceti daca verificarea invariantului se schimba nitel, va trebui sa modificati in fiecare metoda in care el exista.
Dar nu despre multiplicare vorbim azi, lucrurile prezentate au o aplicabilitate mult mai mare si mai interesanta.
Mai mult, daca verificarea constrangerii se modifica si devine din ce in ce mai complexa, atunci creste si metoda care trebuie sa se asigure de aceasta constrangere, dar fara ca functionalitatea ei de baza sa se fi modificat.

Cum ar arata o varianta mai interesanta:

class Container {
private float capacity;
private float contents;
public void pourIn(float addedVolume) {
float volumePresent = contents + addedVolume;
contents = constrainedToCapacity(volumePresent);
}

private float constrainedToCapacity(float volumePlacedIn) {
if (volumePlacedIn > capacity) return capacity;
return volumePlacedIn;
}
}


In acest mod, Constrangerea poate creste cat doreste, pentru ca functia care are nevoie de constrangere ramane la fel de simpla.
Mai mult, prin aceasta varianta, respectam un alt principiu important, „reveal the intention”.
Astfel cine va citi codul va stii exact ce bucata de cod la ce foloseste si mai mult, cei ce vor utiliza clasa, vor stii ca exista aceste constrangeri care trebuie folosite.
Daca lasam bucatile de cot azvarlite prinmetode, riscam ca lumea sa nu inteleaga despre ce e vorba, mai ales daca codul nostru era imbricat si cu alte verificari, sau chiar cod de realizare al functiei respective.

Este aceasta metoda cea mai buna?

Chiar daca acum am separat cele doua bucati de cod, chiar daca avem o noua metoda deci un nou concept despre care putem discuta,
Chiar daca acum constrangerea se poate modifica independent de codul care o foloseste, exista totusi niste situatii cand nu e de ajuns acest pas si trebuie facut inca unul in plus.
Iata cateva semne dupa care sa recunoasteti aceste situatii:
- Evaluarea unei constrangeri necesita date care nu se afla si nu au ce sa caute in definitia obiectului;
- Constrangeri care se afla intr-o relatie, se afla raspandite prin mai multe obiecte, lucru care forteaza duplicarea codului, sau mostenirea inutila intre obiecte care altfel nu formeaza o familie;
- O multime de discutii se poarta pe marginea conceptului reprezentat de o constrangere, dar aceste constrangeri nu sunt explicite in cod, ele fiind adanc ascunse in codul procedural.

Ca si regula generala:
Cand constrangerile ascund functionalitatea reala a obiectului, sau cand constrangerea este prezenta ind discutiile de specialitate, dar nu e prezenta in proiectarea codului nostru, trebuie sa construiti constrangerea ca un obiect separat, sau ca un set de obiecte si relatii intre acestea.

Despre procese!

Un alt aspect important pe care l-am depistat, alaturi de constrangeri si, si, o sa vedeti voi, sunt procesele.
Avem doua tipuri de procese, procese specifice domeniului si procese computationale.
Cele specifice domeniului sunt acele procese despre care utilizatorii softului creat de dumneavoastra vorbesc si ele sunt specifice domeniului in care softul dumneavoastra va actiona.
Procedura de inchiriere a unui bun sau serviciu, modalitatea de calcul a salariilor etc, sunt toate procese de domeniu.
Un proces computational, este un proces care tine de mecanismele de a realiza anumite activitati cu ajutorul unui computer.

Care e problema?

Problema identificata de noi, in softul la care lucram, era aceia ca, peste tot, erau proceduri de genu:
calculeazaSalariuManager()
InchiriazaBarca()
InchiriazaContainer()
CalculeazaDrum()
Si multe altele ca astea, toate intr-un anumit obiect.
Dorinta noastra fierbinte, cand scriem un soft, este aceea de a nu ajunge sa avem toate clasele comportandu-se ca un cod procedural.
Pentru aceasta recomandarea generala este:
Oricand aveti de a face cu un proces specific domeniului, incercati sa il construiti ca un obiect.

Cum sa facem asta?

Pai o prima varianta, atunci cand procesul este unic si nu comporta mai multe variante din care sa se aleaga, este patternul Service (vorbim despre el, intr-o postare urmatoare).
Daca insa procesul respectiv se poate realiza in mai multe variante, variante din care sa se aleaga eventual la momentul rularii, folositi patternul strategy pentru a incapsula intregul algoritm intr-o clasa.

De ce vorbim despre astea?

Constrangerile si procesele sunt doua tipuri de concepte foarte raspandite care nu iti vin in minte la momentul proiectarii unei aplicatii, dar care, odata identificate si introduse in cod, netezesc modelul claselor scrise de noi si imbunatatesc uzabilitatea si intretinerea codului.

Dar unde este java?

Da, da, stiu, aveti dreptate, iar bat campii pe design si nu va arat java.
V-am spus sa ma iertati cand fac asa, promit sa nu se mai intimple, pana data viitoare.
Ajungem si la java imediat, atit java ca o sa va saturati.
Dar mai intai sa ajungem la modelul, paternul, care ne va ajuta sa rezolvam problema constrangerilor, A proceselor si a mai multor lucruri.

Va Urma

In elaborarea acestui articol ne-am sprijinit pe:

Domain-driven design : tackling complexity in the heart of software / Eric
Evans.
p. cm.
Includes bibliographical references and index.
ISBN 0-321-12521-5

Evans, E., and M. Fowler. 1997. "Specifications." Proceedings of PLoP 97 Conference.

vineri, 12 noiembrie 2010

despre interceptie si contraceptie cu java

De ceva vreme, bunul meu prieten, fost coleg (dar tot bun) si discipol (evident bun), m-a invitat sa scriu pe acest blog despre subiectele cu care ma confront in viata mea de zi cu zi de afacerist in lumea software.
Cum blogul sau este despre java, o sa ii pastrez tipicul si ma voi referi numai la subiecte java, sau care au legatura cu java.
O sa ma scuzati daca uneori calc pe alaturi si mai vorbesc despre subiecte cum ar fi, arhitecturi, business, data access, marketing, management, dar promit ca toate exemplele sa fie din java.
Probabil ca daca va veti exprima avantul de cunoastere, voi face un site cu tenta mai generala, denumit software_design sau cum_sa_iti_prajesti_singur_cartofi.
Pentru a nu ii face pe cei riguros professional sa strambe din nas la glumele mele (nu e asa ca fac glume bune?), voi trece abrupt si direct in subiectul de azi.

Context

Sunt de ce in ce mai nervat de cod precum:
Public void metoda(tip parametru)
{
Try
{
If(parametru==null) loger.log(“mesaju”);
If(parametru…) loger.log(“mesaju”);
…..(aici e alt cod)
If(parametru…) loger.log(“alt mesaj”);
….(alt cod)
}
Catch(Exception ex)
{
Loger.log(ex.getMessage());
}
}

Nu vi se pare enervanta imixtiunea asta a tot felul de alte bucati de cod, in codul in care dumneavoastra doriti sa faceti ceva?
Pe mine ma enerveaza spre exemplu cand am de scris o metoda de calcul a dobanzilor trimestriale, cu aplicare zilnica si cu retragere in momentul stricarii unui deposit, sa tot stau sa ma gandesc la tot felul de alte coduri, cum ar fi cel de verificare, cel de exceptii, cel de alta natura decat cel pe care il am de scris.
Eu vreau ca atunci cand scriu o metoda de calcul a dobanzilor, sa scriu despre dobanzi si atit.
Un alt lucru important,
Avem o bucata de cod, compilat, nu avem codul sursa.
Codul ala are o interfata publica si atit.
Dar codul ala nu face exact ce vreau eu, iar ceea ce mi-ar trebui mi ear trebui sa se intimple inainte ca o metoda din interfata publica sa fie chemata, sau atunci cand e pe punctul sa fie chemata, sau imediat dupa ce a terminat de lucrat, dar pana cand se ajunge in codul care a chemat-o.
Spre exemplu, am o metoda de calcul a preturilor, dar respectiva metoda e intr-o clasa unde eu nu pot sa intervin, dar totusi mie mi-ar trebui sa aplic la calcul pretului niste procentaje de penalizare.
Ei bine, veti zice, ce mare lucru, iti calculezi ce valori vrei, dai ca parametru metodei si cu rezultatul intors mai faci niste calcule si gata.
Desigur, merge si asa si asa va face orice programator care nu a depasit pragul programatorului de liceu.

Ce variante avem:

Ca sa ridicam putin nivelul de lucru, sa trecem de la liceu la facultate, prezentam urmatoarele posibilitati.
O prima posibilitate este patern-ul decorator, cine il stie il stie, cine nu aia e, inseamna ca postarea asta nu se ridica inca la nivelul vostru.
Prin acest patern, extindem clasa pe care o dorim, detinem si o copie a clasei respective inauntru si scriem metode de inlocuire pentru toate metodelepe care dorim sa le alteram.
O alta solutie este oferita de patern-ul adapter (din nou, cine nu il stie, la carte si cititi despre).
Acest patern decupleaza patern-ul decorator in doua paterne diferite.
Paternul nr 1, adapter prin extindere. Adica cu clasa noastra extindem clasa ce dorim sa ii alteram comportamentul.
Patern-ul nr. 2, adapter prin compozitie, adica creiem o noua clasa, care va fi un wrapper pentru clasa ce dorim sa o modificam si scriem metode de inlocuire pentru cele care dorim sa le alteram de la clasa initiala.
De ce am avea nevoie de un adapter prin compozitie daca tot il avem pe cel de extindere?
Asta e un alt subiect interesant si este strans legat de principiul inlocuirii al lui Liskov, despre care, daca veti dori, vom avea o alta discutie.

Dar unde este Java?

Aveti dreptate, am palavragit pana acum fara sa vedem putin cod java.
O solutie si mai interesanta, s-ar putea obtine folosind programare orientata pe aspecte (intr-un post urmator vorbim despre asta).
In principiu aceasta paradigma introduce notiunile de punct de join si punct de taiere.
Si poate interveni in momentele enumerate mai sus legate de metoda.
Un alt patern care ne poate oferi o solutie si care ne adduce mai aproape de programarea orientata pe aspecte, este patern-ul Proxy (cred ca deja o sa vreti sa va vorbesc despre fiecare, ca v-am enumerat mai multe, nu e nimic, avem loc de scris in posturi urmatoare).
Imprumutand putin din patern-ul proxy, putin din programarea orientata pe aspecte, java ne pune la dispozitie o caracteristica foarte interesanta pentru a rezolva aceasta problema.
Sa vedem cum functioneaza.
Tot odata, va voi prezenta ceea ce urmeaza ca un principiu de urmat, atunci cand va scrieti propriul cod.

Folositi puncte de interceptie pentru a adauga optimizari, particularizari sau functionalitati noi

Incepand cu java 1.3, java permite ceea ce se cheama proxy dynamic, permitand programatorilor sa scrie un proxy dynamic care implementeaza o interfata pentru un obiect classic care implementeaza aceeasi interfata (intr-un fel ca la decorator).
Ca sa ne exprimam in romana, proxy dynamic permite programatorului sa scrie cod de interceptare in jurul unui obiect normal, atit timp cat obiectul respectiv este apelat/folosit printr-o interfata.
Sa ne intoarcem putin la exemplul cu logerul si sa vedem cum putem adauga mecanismul de loging fara a schimba tot codul.
In loc sa apelam cine stie ce jiumbuslucuri de cod, mai de graba folosim un mechanism clasa I! Si anume mecanismul de proxy dynamic pus in fata fiecarui obiect pe care il dorim cu mechanism de loging, avand grija ca acest obiect sa fie folosit printr-o interfata:

public class LoggingProxy

implements InvocationHandler

{

public static Object

newLoggingProxyAround(Logger logger, Object obj)

{

return Proxy.newProxyInstance(

obj.getClass().getClassLoader(),

obj.getClass().getInterfaces(),

new LoggingProxy(logger, obj));

}



private Object proxiedObject;

private Logger logger;



private LoggingProxy(Logger l, Object obj)

{

logger = l;

proxiedObject = obj;

}



public Object invoke(Object proxy,

Method m, Object[] args)

throws Throwable

{

Object result;

try

{

l.info("Entering method " + m.getName());

result = m.invoke(proxiedObject, args);

}

catch (Exception x)

{

l.warn("Unexpected exception " + x + " invoking "

+ m.getName());

throw x;

}

finally

{

l.info("Exiting method " + m.getName());

}

return result;

}

}


Un logingproxy se va comporta ca un wrapper pentru fiecare obiect in jurul caruia este construit (Utilizand metoda Factory newLoggingProxyAround) si va scrie mesaje de log pentru fiecare chemare de metoda care va veni prin interfata respectiva.
Il vom utiliza dupa cum urmeaza:


public interface Person

{

public String getFirstName();

public void setFirstName(String value);

public String getLastName();

public void setLastName(String value);

public int getAge();

public void setAge(int value);

}


public class PersonImpl

implements Person

{

//alte detalii

private String fname;

private String lname;

private int age;

public String getFirstName() { return fname; }

public void setFirstName(String value) { fname = value; }

public String getLastName() { return lname; }

public void setLastName(String value) { lname = value; }



public int getAge() { return age; }

public void setAge(int value) { age = value; }

}

public class PersonManager

{

public Logger personLogger = ...; //o instanta a unui logger

public boolean loggingEnabled = false;

// Set pe true pentru a porni logging



public static Person

getPerson(String firstName, String lastName)

{

Person p = new PersonImpl();

// Obtinerea persoanei de undeva; intr-un system real

// persoanele vor fi intr-o baza de date sau undeva

// asemanator

//



if (loggingEnabled)

p = (Person)

LoggingProxy.newLoggingProxyAround(personLogger, p);



return p;

}

}


Dupa cum ati vazut, pentru a construe o persoana, folosim metoda statica Factory getPerson.
Aceasta primeste datele necesare despre o persoana, se uita in baza de date, sau unde se afla persoanele si obtine toate datele necesare,
Apoi construieste o instanta a clasei concrete.
Utilizam aceasta metoda statica, pentru a introduce un pas in plus in creierea persoanei.
Amintiti-va, tot ce am dorit a fost sa introducem loging inauntru obiectelor respective.
Deoarece nu putem, sau mai de graba nu vrem sa modificam bytecode-le existent, am emis doar cate un mesaj la inceputul si sfarsitul apelului unei metode.
Deci vom prezenta un obiect interceptor inaintea obiectului propriuzis; Interceptorul va avea o referinta catre PersonImpl si va trimite mai departe catre PersonImpl toate apelurile de metoda pe care le va primi, dar numai dupa ce va afisa un mesaj de log.
Frumusetea acestei abordari este ca, indifferent de tipul obiectului pentru care implementam loging, interceptia metodelor functioneaza.
Cheia este ca proxy-ul are nevoie, pentru a trimite apelurile catre obiectul real (PersonImpl in exemplul de fata), sa treaca printr-o interfata mai de graba decat printr-o clasa concreta.
De aceea PersonManager returneaza Person si nu PersonImpl.
Mai mult, nu exista nici-o relatie de structura la momentul compilarii intre Person si actul de logging.
In schimb, logging-ul poate fi pornit sau oprit, prin simpla modificare a variabilei boolene LogingEnabled, care poate fi un element in configurarea aplicatiei.
Construind componente in loc de obiecte, vom putea folosi interceptorii pentru a introduce in ce mod dorim comportamentul necesar, fara sa schimbam codul specific pentru un domeniu, sau codul de interfata cu clientii.
Folositi interfete pentru a defini ce vor vedea clientii, folositi metode statice Factory pentru constructia de obiecte, ascundeti implementarea reala a unui obiect in spatele unuia sau mai multor proxy-uri dinamice care sa implementeze functionalitatea transversala dorita.
Ca bonus, am obtinut (gratis) “cuplare slaba” intre componente, deoarece implementarea reala a obiectelor se poate schimba nestingherit, fara ca clientii sa stie sau sa le pese de asta.

Va multumesc mult pentru ca ati avut rabdare pana la final,
Astept opiniile voastre si sugestii despre ce ati dori sa vedeti publicat.
Daca aveti probleme pe care nu puteti sa le rezolvati, sau ati dori sa vedeti solutia noastra, le asteptam.
Mentionez ca pentru acest material am utilizat (pentru reamintiri exacte) cartea
Effective Enterprise Java
By Ted Neward
-
Publisher-: Addison Wesley Professional
Pub Date-: August 26, 2004
ISBN-: 0-321-13000-6
Pages-: 496

sâmbătă, 24 aprilie 2010

Compara date calendaristice

Aseara lucram la un program de pontaj cand, la un moment dat m-am lovit de urmatoarea problema. Aveam un obiect care avea ca atribute o data de inceput si o data de sfarsit(obiectul concediu) vroiam sa marchez in foaia de pontaj concediile si eventualele invoiri in functie de atributele precizate. Zis si facut...continui prin a va prezenta logica programului :

1 /* Metoda care verifica daca o data calendaristica se afla intr-un interval de date calendaristice
2 Folosim metoda compareTo a obiectului Date, metoda care returneza -1,0,1(mai mic,egal,mai mare)
3 */
4 private boolean dataInInterval(Date dataC,Date dataS,Date dataE){
5 if(dataC.compareTo(dataS)>=0 && dataC.compareTo(dataE)<=0){
6 return true;
7 }
8 return false;
9 }
10 //obiectul Concediu are printre atributele sale dataStart si dataEnd de tip Date
11 //initializam arrayListul de concedii
12 ArrayList<Concediu> concedii=concediiDinBD.getConcedii();
13 //initializam un obiect de tip calendar
14 Calendar lunaCurenta=Calendar.getInstance();
15 //extragem ultima zi din luna curenta pentru a o folosi in for
16 int ultimaZiDinLuna=lunaCurenta.getActualMaximum(Calendar.DAY_OF_MONTH);
17 for(int i=1;i<=ultimaZiDinLuna;i++)
18 {
19 lunaCurenta.set(Calendar.DAY_OF_MONTH, i);
20 //aici apelam metoda normalizare(lunaCurenta.getTime) - metoda este descrisa in continuare
21 for(int j=0;j<concedii.size();j++)
22 {
23 if(dataInInterval(lunaCurenta.getTime(),concedii.get(i).getDataStart(),concedii.get(i).getDataEnd())){
24 //marcheaza concediile sau eventualele invoiri in foaia de pontaj
25 }
26 }
27 }

Contrar asteptarilor mele acest cod nu a functionat cum m-as fi asteptat...
Evaluarea conditiei(dataC.compareTo(dataS)>=0 && dataC.compareTo(dataE)<=0) pentru valorile dataC=lunaCurenta.getTime(), dataS=24/04/2010 si dataE=24/04/2010 unde lunaCurenta.getTime()=24/04/2010 a fost spre surprinderea mea false; Dupa ce am rascolit internetul am aflat ca, deoarece valorile atributelor obiectului Concediu(dataS,dataE) vin din baza de date,deci sunt obiecte de tip java.sql.Date(asta nu ar trebui sa fie nici o problema) in momentul in care un obiect de tip java.util.Date si un obiect de tipul java.sql.Date sunt comparate, ele sunt comparate la nivel de milisecunda...In opinia mea ar trebui lasat la latitudinea programatorului...Deci, practic in conditia mea, desi aveam dataC.compareTo(dataS) ceea ce ar fi trebuit sa imi compare datele, comparatia se face la nivel de milisecunda.

Rezolvarea?

Pai avand in vedere ca obiectul de tip java.sql.Date care vine din bd vine atributele ora,minut,secunda si milisecunda egale cu 0, vom seta si noi obiectul nostru lunaCurenta(de tip calendar) cu aceste valori, pastrand valorile year,month si day.


28 private void normalizare(Calendar cal) {
29 cal.set(Calendar.MILLISECOND, 0);
30 cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
31 }
32


Deci problema noastra se poate rezolva prin apelarea metodei normalizare(lunaCurenta.getTime()) inainte de a intra in for-ul in care testam valoarea functiei dataInInterval

In speranta ca aceasta constatare va ajuta si pe altcineva,

Va multumesc pentru rabdarea de a citit tot ce am scris.