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.

Niciun comentariu:

Trimiteți un comentariu

Va rugam lasati un comentariu!