92
SVEUČILIŠTE U ZAGREBU FAKULTET ORGANIZACIJE I INFORMATIKE V A R A Ž D I N Danijel Filipović UZORCI DIZAJNA ZA PODATKOVNI SLOJ DIPLOMSKI RAD Varaždin, 2017.

DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

  • Upload
    others

  • View
    6

  • Download
    0

Embed Size (px)

Citation preview

Page 1: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

SVEUČILIŠTE U ZAGREBU

FAKULTET ORGANIZACIJE I INFORMATIKE

V A R A Ž D I N

Danijel Filipović

UZORCI DIZAJNA ZA PODATKOVNI SLOJ

DIPLOMSKI RAD

Varaždin, 2017.

Page 2: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

SVEUČILIŠTE U ZAGREBU

FAKULTET ORGANIZACIJE I INFORMATIKE

V A R A Ž D I N

Danijel Filipović

Matični broj: 44423/15-R

Studij: Baze podataka i baze znanja

UZORCI DIZAJNA ZA PODATKOVNI SLOJ

DIPLOMSKI RAD

Mentor:

Prof. dr. sc. Dragutin Kermek

Varaždin, rujan 2017.

Page 3: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

III

1. Uvod ....................................................................................................................................... 1

2. Osnovne ideje primjene uzoraka dizajna ............................................................................... 2

2.1. Zašto se koriste uzorci dizajna?....................................................................................... 2

2.2. Kako uzorci dizajna rješavaju probleme u dizajnu? ........................................................ 3

3. Predložak za opis uzoraka dizajna ......................................................................................... 5

3.1. Usporedna analiza ........................................................................................................... 5

3.2. Struktura korištenog predloška ........................................................................................ 7

4. Uzorci dizajna za podatkovni sloj .......................................................................................... 8

4.1. Identity Field ................................................................................................................... 9

4.2. Identity Map .................................................................................................................. 11

4.3. Repository ...................................................................................................................... 14

4.4. Ostali uzorci dizajna ...................................................................................................... 17

5. Uzorci dizajna za rad s bazom podataka .............................................................................. 20

5.1. Active Record................................................................................................................. 21

5.2. Data Mapper ................................................................................................................. 29

5.3. Row Data Gateway ........................................................................................................ 35

5.4. Query Object ................................................................................................................. 41

5.5. Table Data Gateway ...................................................................................................... 49

5.6. Unit of Work .................................................................................................................. 54

6. Uzorci dizajna za ORM sustave ........................................................................................... 59

6.1. Uzorci dizajna za preslikavanje ..................................................................................... 59

6.2. Uzorci dizajna hijerarhije nasljeđivanja tablica ............................................................ 60

6.3. Uzorci dizajna za mnogostrukost veza između relacijskih tablica ................................ 60

6.4. Embedded Value ............................................................................................................ 61

6.5. Identity Field ................................................................................................................. 61

6.6. Identity Map .................................................................................................................. 61

6.7. Query Object ................................................................................................................. 62

6.8. Unit of Work .................................................................................................................. 62

7. Refaktoriranje podatkovnog sloja ........................................................................................ 63

7.1. Refaktoriranje programskog koda ................................................................................. 63

7.2. Refaktoriranje baze podataka ........................................................................................ 66

8. Aplikacija ............................................................................................................................. 70

8.1. Opis aplikacije ............................................................................................................... 70

8.2. Korištene tehnologije .................................................................................................... 71

8.3. Struktura baze podataka ................................................................................................ 72

8.4. Klase entiteta ................................................................................................................. 76

8.5. Korišteni uzorci dizajna ................................................................................................ 79

Page 4: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

IV

8.6. EntityMapper i EntityMap ............................................................................................. 84

9. Zaključak .............................................................................................................................. 87

Literatura .................................................................................................................................. 88

Page 5: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

1

1. Uvod

Cilj ovog rada je izdvojiti i opisati uzorke dizajna koje bi se koristile u podatkovnom sloju za različite

računalne aplikacije. Specifično, izdvojiti će se i opisati uzorci dizajna za podatkovni sloj aplikacije i uzorci

dizajna koji bi se koristili za rad s bazom podataka.

Objasniti će se osnovne ideje primjene uzorka dizajna, tj. objasniti će se zašto se koriste uzorci dizajna i kako

uzorci dizajna rješavaju probleme koji se pojavljuju u dizajnu računalnih sustava. Nakon toga će se u

zasebnom poglavlju odrediti struktura po kojoj će se opisati uzorci dizajna. Također će se u istom poglavlju

spomenuti zašto je potrebno odrediti strukturu opisa uzoraka dizajna.

Zatim, krenut će se s opisom uzoraka dizajna. Uzorci će biti podijeljeni u dvije kategorije, odnosno dva

poglavlja:

• uzorci dizajna za podatkovni sloj i

• uzorci dizajna za rad s bazom podataka,

Svaki uzorak dizajna će biti opisan prema definiranoj strukturi i, u sklopu te strukture, ti opisi će biti

popraćeni s primjerom u programskom jeziku Java.

Nakon objašnjenja uzoraka dizajna u spomenutim poglavljima, zasebno poglavlje biti će posvećeno

objašnjavanju koji od opisanih uzoraka dizajna bi se mogli koristiti u ORM (object-relational mapping)

sustavima1. Poslije toga, slijedi poglavlje posvećeno refaktoriranju na razini podatkovnog sloja.

Zatim, slijedi poglavlje o aplikaciji koja je izrađena u sklopu ovog rada. Aplikacija neće biti objašnjena u

tom poglavlju, već će biti objašnjeni samo dijelovi aplikacije koji se odnose na uzorke dizajne. Poglavlje o

aplikaciji sadržavat će opis aplikacije, opis korištenih tehnologija te opis implementacija uzoraka dizajna.

Opis implementacija biti će popraćeno programskim kodom. Nakon toga, slijedi zaključak cijelog rada.

1ORM sustavi preslikavaju relacijske tablice iz baze podataka u objekte za objektno-orijentirane sustave (i obratno).

Jedan red u relacijskoj tablici predstavlja jedan objekt u OO sustavu.

Page 6: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

2

2. Osnovne ideje primjene uzoraka dizajna

Kod objašnjavanja pojma uzorka dizajna autori knjiga, osobito Gamma et al. (1995), Buschmann et

al. (1996) i Fowler (2003), se referenciraju i citiraju arhitekta Alexander Christopher. Christopher je bio

arhitekt, ali njegovo objašnjenje za pojam "uzorak", iako se koristio u kontekstu arhitekture kuća i zgrada,

mnogi autori smatraju prigodnim i u kontekstu programske arhitekture.

Objašnjenje pojma uzoraka dizajna glasi otprilike ovako (Gamma et al., 1995:2; Fowler, 2003:9-10): "Svaki

uzorak opisuje problem koji se stalno pojavljuje u našoj okolini i opisuje osnovno rješenje tog problema na

takav način da se to rješenje može koristiti milijun puta bez ponavljanje načina na kojem je napravljeno."

Ukratko rečeno, uzorak dizajna opisuje problem u dizajnu programske arhitekture i opisuje rješenje tog

problema. Potrebno je napomenuti da uzorak dizajna izričito opisuje rješenje, a ne daje rješenje. Uzorak

dizajna je apstraktne prirode, odnosno ono je predložak kojeg programer može urediti po potrebi kako bi ga

primijenio u kontekstu svoje aplikacije , čime se ostvaruje osobina ponovne iskoristivosti uzoraka (Gamma

et al., 1995:2-3).

Dalje, u ovom poglavlju, razmotriti će se zašto se koriste uzorci dizajna u rješavanju specifičnih problema u

dizajnu programske arhitekture i kako baš oni rješavaju takve probleme.

2.1. Zašto se koriste uzorci dizajna?

Uzorci dizajna se temelje na postojećoj i dobro priznatoj praksi. U knjigama od Gamma et al. (1995) i

Buschmann et al. (1996) kao primjer jednog takvog uzorka dizajna koji je priznat od strane prakse koriste

uzorak Model-View-Controller (nadalje MVC). Po uzoru na te dvije knjige, i ovdje će se ukratko objasniti

spomenuti uzorak dizajna u nadi lakšeg razumijevanja zašto se koriste uzorci dizajna.

MVC je uzorak dizajna za interaktivne sustave koji dijeli aplikaciju na tri komponente (Buschmann et al.,

1996:125-127):

• Model

◦ Sadrži podatke s kojima radi aplikacija i također implementira osnovnu funkcionalnost

aplikacije.

• View

◦ Koristi se za prikaz informacija korisniku. Podaci, koji se koriste u prikazu, se dohvaćaju iz

model-a. Za jedan model može postojati više view-ova.

• Controller

◦ Prima i obrađuje događaje (eng. events) nastale korisničkom interakcijom sa sustavom. Za svaki

view postoji jedan controller.

Prednost uzorka dizajna MVC je što nam ono omogućava da mijenjamo jednu od navedenih tri komponenti

bez značajnog utjecaja na ostale komponente. Npr. ako želimo promijeniti način na koji se prikazuju podaci,

samo će se promijeniti view komponenta dok model komponentu ne treba ni taknuti. Ako se želi promijeniti

Page 7: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

3

način na koji se obrađuje neki događaj nastao korisničkom interakcijom, tada će se promijeniti samo

controller komponenta. Može postojati slučaj gdje promjena u view komponenti povlači i promjenu u

controller komponenti (moguće i obratno), ali to je uglavnom u slučajevima gdje bi događaj nastao iz view

komponente, npr. klik na gumb koji je prikazan u view-u.

Iako MVC nije primjer uzorka dizajna za podatkovni sloj, ono je dobar primjer za shvaćanje zašto bi

programer koristio ili barem razmotrio korištenje uzoraka dizajna u vlastitim aplikacijama.

2.2. Kako uzorci dizajna rješavaju probleme u dizajnu?

Dizajniranje arhitekture računalnog sustava ponekad nije jednostavan posao. U objektno-

orijentiranom programiranju potrebno je cijeli sustav rastaviti na objekte. Nakon toga treba definirati veze

između tih objekata, odnosno način na koji ti objekti međusobno komuniciraju. Treba razmotriti kakva

sučelja trebaju nasljeđivati objekti konkretnih klasa ili pak treba definirati jednu klasu čije ponašanje će biti

podijeljeno i prošireno putem njenih podklasa. Također postoji pitanje kreiranja fleksibilnih sustava. Sve te

zadaće, i vjerojatno još više njih, programer susreće tijekom razvoja računalnog sustava, odnosno tijekom

dizajna sustava.

Zato, uzorci dizajna mogu riješiti mnoge takve probleme vezane uz dizajn računalnog sustava i, u neku ruku,

bolje podučiti o objektno-orijentiranom programiranju.

Uzorci dizajna nam mogu pokazati koje apstrakcije ulaze u rješenje nekog problema, bilo da se te apstrakcije

pojavljuju u prirodi ili ne, i pretvoriti ih u objekte (Gamma et al., 1995:12-13). Također nam mogu dati uvid

u količinu objekata koji su potrebni za realizaciju rješenja problema (Gamma et al., 1995:13).

Sučelja, apstraktne klase i konkretne klase su elementi objektno-orijentiranog programiranja. Tijekom

dizajna sustava neiskusnim programerima je ponekad teško zamisliti treba li za neku konkretnu klasu

definirati sučelje ili treba li ta konkretna klasa naslijediti i proširiti ponašanje neke apstraktne klase ili druge

konkretne klase. Gamma et al. (1995:17) govore o razlikama između dviju vrsta nasljeđivanja:

• Klasno nasljeđivanje se koristi kada se želi ponašanje neke klase dijeliti s drugim klasama ili kada

se želi proširiti postojeće ponašanje neke klase putem podklasa.

• Nasljeđivanje sučelja, uz to što ograničava ponašanje klasa koje implementiraju sučelje na

deklarirane metode, također služi kao osnovni tip i svaka klasa koja nasljeđuje to sučelje definira

vlastiti podtip.

Uzorci dizajna ovdje pomažu jer u svojim rješenjima, odnosno strukturama rješenja, opisuju koji objekti

sudjeluju u rješenju i koja sučelja ili klase ti objekti moraju naslijediti, ako ih neki objekt uopće treba

naslijediti.

No, dosad se govorilo o tome kako uzorci dizajna rješavaju probleme u dizajnu na nižoj razini, tj. na razini

objekata, veza između objekata, klasa, sučelja, itd. Treba spomenuti i kako uzorci dizajna rješavaju probleme

u dizajnu na višoj razini, odnosno na razini softvera koji se gradi.

Buschmann et al. (1996:7) govore kako uzorci dizajna pružaju "kostur" funkcionalnosti što omogućuje

Page 8: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

4

programerima da na taj "kostur" dodaju ostatak osmišljene funkcionalnosti. Isti autori također uzorke dizajna

opisuju kao pred-definirane artefakte dizajna koji se mogu koristiti kao gradbeni blokovi (eng. building

blocks) za izgradnju arhitekture nekog računalnog sustava.

Zaključno, uzorci dizajna se mogu koristiti kao sredstva za rješenje nekog problema u dizajnu koji je nastao

tijekom razvoja ili kao temelj za razvoj arhitekture računalnog sustava.

Page 9: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

5

3. Predložak za opis uzoraka dizajna

Stručne knjige za uzorke dizajna, kao što su to knjige od Gamma et al. (1995), Buschmann et al.

(1996) i Fowlera (2003), napravljene su kao jedan oblik kataloga uzoraka dizajna. Za opis uzoraka dizajna

autori su odredili predložak prema kojem opisuju pojedini uzorak dizajna. Iako ovaj rad nije zamišljen kao

stručna literatura za uzorke dizajna, ipak će se odrediti predložak po kojem će se opisati uzorci dizajna za

podatkovni sloj.

Gamma et al. (1995) i Buschmann et al. (1996) u svojim knjigama su odredili detaljan predložak za opis

uzoraka dizajna, dok je Fowler (2003) odredio znatno jednostavniji predložak koji, u određenim slučajevima,

nije u potpunosti koristio. Uzorci dizajna koji su opisani u ovom radu izvučeni su iz Fowlerove knjige, ali za

te uzorke određen je poseban, vlastiti, predložak za njihov opis koji se koristi u ovom radu.

Nadalje, u ovom poglavlju napraviti će se usporedna analiza predloška za opis uzoraka dizajna koje su

korištene u knjigama od Gamma et al. (1995), Buschmann et al. (1996) i Fowler (2003). Nakon spomenute

analize, pokazati će se struktura predloška koji se koristi za opis uzoraka dizajna u ovom radu.

3.1. Usporedna analiza

U ovoj analizi usporediti će se predlošci koje koriste Gamma et al. (1995), Buschmann et al. (1996)

i Fowler (2003). Specifično, uspoređivati će se koji elementi uzorka dizajna jesu ili nisu opisani u odabranim

predlošcima te, ako jesu, gdje u strukturi svakog predloška jesu opisani.

Jedan od elemenata koji je uključen u sva tri spomenuta predloška je naziv uzorka dizajna. Važno je uzorcima

dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između

programera (Fowler, 2003:119). Gamma et al. (1995) i Buschmann et al. (1996) u svojim knjigama također

navode alternativne nazive za opisujuće uzorke, što Fowler (2003) u svojoj knjizi nema.

Svi autori opisuju namjere uzorka dizajna, odnosno u par rečenica opisuju što uzorak dizajna radi. Gamma

et al. (1995) navodi namjeru pod posebnim elementom (Intent, hrv. namjera) dok ih Fowler (2003) navodi

kao dio uvoda u uzorak dizajna. Buschmann et al. (2003) daje kratak opis uzorka u imenu uzorka dizajna.

Svi autori opisuju problem kojeg uzorak dizajna rješava i također detaljno opisuju rješenje te spomenuto

rješenje funkcionira. No, sva tri autora problem i rješenje objašnjavaju na različite načine. Kod predloška od

Buschmann et al. (1996) definiran je poseban element u kojem se opisuje problem i poseban element u kojem

se opisuje rješenje. Gamma et al. (1995:6-7) problem i rješenje opisuju pod Motivation (hrv. motivacija) gdje

opisuju scenarije gdje se pojavljuje problem u dizajnu i kako objektna i klasna struktura vezana za opisujući

uzorak dizajna rješava taj problem. Fowler (2003) problem opisuje u svojevrsnom uvodu u uzorak dizajna, a

rješenje opisuje, odnosno diskutira, pod How It Works (hrv. kako radi).

Također, svi autori opisuju i situacije u kojima su opisujući uzorci dizajna primjenjivi. Gamma et al. (1995)

opisuje takve situacije pod Applicability (hrv. primjenjivost), Buschmann et al. (1996) ih opisuje pod Context

(hrv. kontekst) i Fowler (2003) ih opisuje pod When To Use It (hrv. kada koristiti).

I Gamma et al. (1995) i Buschmann et al. (1996) određuju poseban element u strukturi predloška u kojem

Page 10: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

6

prikazuju strukturu rješenja kao dijagram klasa. Gamma et al. (1995:7) također, u nekim uzorcima dizajna,

koriste dijagram sekvence za prikaz komunikacije između objekata koji sudjeluju u uzorku, a Buschmann et

al. (1996:20) uz dijagram klasa koristi i CRC kartice (eng. CRC Cards). Također, Buschmann et al. (1996:20-

21) pod Dynamics (hrv. dinamika) pomoću dijagrama sekvence prikazuju ponašanje objekata tijekom rada.

Fowler (2003) ne određuje poseban element predloška u kojem grafički prikazuje strukturu rješenja

opisujućeg uzorka dizajna. Naime, autor u uvodu u uzorak dizajna koristi grafičku reprezentaciju uzorka

dizajna i to uglavnom dijagram klasa, ER model ili, u određenim situacijama, proizvoljnu sliku. Isti autor

također zna koristiti dijagram klasa, ER model ili sekvencijalni dijagram u drugim elementima predloška kao

pomoć pri objašnjavanju.

Predložak od Gamma et al. (1995:7) sadrži element u kojima opisuje objekte i klase koji sudjeluju u realizaciji

uzorka dizajna te koja su njihova zaduženja (Participants, hrv. sudionici) i element u kojem objašnjava kako

ti navedeni sudionici surađuju (Collaborations, hrv. suradnje). Predložak od Buschmann et al. (1996) ne

sadrži takve elemente, ali suradnju između objekata je objašnjavaju kao komunikaciju između objekata i

prikazuju pomoću dijagrama sekvenci pod Dynamics.

Svi autori u svojim predlošcima daju upute za implementaciju opisujućeg uzorka dizajna. Gamma et al. (1995)

i Buschmann et al. (1996) u svojoj strukturi predloška sadrže element Implementation (hrv. implementacija),

dok Fowler (2003) o implementacijskim detaljima raspravlja pod How It Works.

Gamma et al. (1995) i Buschmann et al. (1996) u svojim opisima uzoraka dizajna navode poznate primjene

opisujućeg uzorka. Za to su definirali poseban element strukture predloška za opis uzoraka dizajna, Known

Uses (hrv. poznate primjene). Fowler (2003) takvo nešto nema u strukturi svog predloška, već koristi samo

jednostavne i razumljive primjere.

Gamma et al. (1995:7) u svom predlošku definira element Consequences (hrv. posljedice) u kojem opisuje

rezultate i kompromise korištenja opisujućeg uzorka dizajna. Buschmann et al. (1996) takvo nešto ne sadrži

u strukturi predloška. Fowler (2003:11) opisuje prednosti i nedostatke opisujućeg uzorka pod How It Works,

te opisuje koji su kompromisi odabira tog uzorka dizajna u usporedbi s nekim drugim uzorkom dizajna pod

When To Use It.

Buschmann et al. (1996) u svom predlošku definira elemente Variants (hrv. varijante) i See Also (hrv. vidi

također). Prvi element opisuje razne varijante i specijalizacije opisujućeg uzorka, dok u drugome se

referencira na uzorke dizajna koji ili rješavaju sličan problem ili se poboljšavaju uzorak koji se opisuje

(Buschmann et al. 1996:21). Gamma et al. (1995) ne sadrži takve opise, nego u svom predlošku definira

element Related Patterns (hrv. povezani uzorci) u kojem opisuje uzorke dizajna koji su povezani s opisujućim

uzorkom, koje su im razlike te s kojim uzorcima dizajna se opisujući može zajedno koristiti. Fowler (2003)

ne sadrži išta od navedenoga, već tijekom opisa uzoraka dizajna ponekad referencira druge uzorke u svojoj

knjizi radi usporedbe.

Na kraju, po vlastitom mišljenju i veoma važno, svi već spomenuti autori u svojim knjigama definiraju

element u strukturi predloška u kojoj pokazuju primjer implementacije uzorka dizajna.

Page 11: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

7

3.2. Struktura korištenog predloška

Predložak za opis uzoraka dizajna koji će se koristiti u ovom radu sadrži sljedeće elemente:

• Naziv

◦ Učahuruje opis problema, rješenja i ostalih elemenata koje obuhvaća uzorak dizajna i proširuje

rječnik dizajna. Svaki uzorak dizajna će imati svoje potpoglavlje unutar 4. i 5. poglavlja, a naziv

uzorka će biti ujedno biti i naziv potpoglavlja.

• Namjera

◦ Kratak opis što radi uzorak dizajna koji se opisuje.

• Problem

◦ Opisuje problem u dizajnu koji se rješava primjenom uzorka dizajna.

• Rješenje

◦ Opisuje rješenje, odnosno kako uzorak dizajna rješava problem u dizajnu te ograničenja tog

uzorka.

• Struktura rješenja

◦ Dijagram klasa koji prikazuje klase koje ulaze u rješenje i u kakvoj su međusobnoj vezi.

Struktura rješenja neće biti moguća za sve uzorke dizajna koji su opisani u ovom radu.

• Primjer

◦ Jednostavan primjer implementacije uzorka dizajna u programskom jeziku Java ili, u nekim

slučajevima, kao UML dijagram.

Page 12: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

8

4. Uzorci dizajna za podatkovni sloj

U ovom poglavlju opisati će se uzorci dizajna koji su specifični za podatkovni sloj aplikacija. Kao

što se može zaključiti prema imenu, podatkovni sloj aplikacija je sloj orijentiran na podatke i uglavnom se

sastoji od:

1. podataka pohranjenih u bazi podataka (npr. u relacijskoj bazi podataka poput PostgreSQL),

2. reprezentacija tih podataka u aplikaciji koja ih koristi (npr. u obliku objekata u programskom jeziku

Java),

3. komunikacije između aplikacije i baze podataka radi izvršavanja operacija kreiranja, čitanja,

ažuriranja i brisanja podataka.

Ovo poglavlje fokusirano je više na uzorke dizajna vezane za prvi i drugi element podatkovnog sloja, dok je

poglavlje 5. Uzorci dizajna za rad s bazom podataka fokusirano na treći element podatkovnog sloja.

Određeni uzorci dizajna mogu pojednostaviti i, u neku ruku, obogatiti podatkovni sloj na razne načine. Neki

uzorci mogu pokazati kako spriječiti kreiranje istog objekta nekog podatka više puta (Identity Map), a neki

uzorci mogu predložiti arhitekturu baze podataka koja bi podržavala različite vrste zavisnosti između

objekata (Foreign Key Mapping, Association Table Mapping).

Nadalje u ovom poglavlju, opisati će se razni uzorci primjenjivi na podatkovnom sloju, a za njihov opis

koristiti će se vlastiti predložak za opis uzoraka dizajna opisan u poglavlju 3. Predložak za opis uzoraka

dizajna.

Page 13: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

9

4.1. Identity Field

4.1.1. Namjera

Sprema identifikacijsko polje (primarni ključ) tablice iz baze podataka u objekt kako bi se održao

identitet između objekta u memoriji i reda u bazi podataka (Fowler, 2003:216).

4.1.2. Problem

U relacijskim bazama podataka primarni ključevi se koriste kako bi se razlikovali redovi unutar neke

tablice, ali objekti u memoriji ne zahtijevaju primarni ključ kako bi se razlikovali već svaki objekt ima svoju

referencu (Fowler, 2003:216). Problem se pojavljuje kada objekt u memoriji treba zapisati, odnosno ažurirati,

u bazi podataka.

4.1.3. Rješenje

Rješenje je veoma jednostavno: atribut primarnog ključa iz relacijske tablice treba imati

idgovarajuće polje u objektu za pohranu. No, Fowler (2003:216) navodi nekoliko problema koji se tiču

odabira primarnog ključa.

Prvi problem kod odabira primarnog ključa je odabir značajnog ili beznačajnog ključa. Značajan ključ može

biti OIB neke osobe. Beznačajan ključ je ključ čiju vrijednost automatski generira neka aplikacija ili sama

baza podataka. Iz vlastitog iskustva, preporučuje se korištenje beznačajnih ključeva za identifikaciju redova

u relacijskoj tablici, a ono što bi se smatralo značajnim ključem koristiti samo kao dodatan atribut u tablici.

Drugi problem kod odabira primarnog ključa je odabir jednostavnog ključa ili složenog ključa. Primarni ključ

je ključ koji se sastoji samo od jednog atributa. Složeni ključ se sastoji od dva ili više atributa. Jednostavni

ključ je najjednostavniji za implementaciju u objektu jer je potrebno dodati jedno polje čiji tip podatka

odgovara tipu podatka u bazi podataka (ako je u bazi podataka INTEGER, onda se u objektu može koristiti

int ili long). Za složeni objekt bi trebalo kreirati posebnu klasu koja bi držala listu varijabli koji odgovaraju

odabranim članovima složenog ključa u bazi podataka (Fowler, 2003:218).

Treći problem kod odabira primarnog ključa je odabir tipa podatka za ključ. Fowler (2003:217) preporučuje

korištenje tipova podataka u kojima se usporedba jednakosti brzo izvršava. To su uglavnom cjelobrojni tipovi

podataka.

Zadnji problem kod odabira primanog ključa je odabir između ključa koji je jedinstven na razini tablice (eng.

table-unique key) i ključa koji je jedinstven na razini baze podataka (eng. database-unique key).

Pretpostavimo da se primarni ključevi generiraju na temelju sekvenci u bazi podataka. U slučaju ključeva

koji su jedinstveni na razini tablice, svaka tablica bi imala svoju sekvencu koja generira vrijednost primarnog

ključa. U slučaju ključeva koji su jedinstveni na razini baze podataka, postoji jedna sekvenca za sve tablice

u bazi podataka. Drugi slučaj bi olakšavao implementaciju uzorka dizajna Identity Map jer bi postojala samo

jedna mapa koja bi pohranjivala sve podatke.

Fowler (2003:218-219) također opisuje probleme generiranja vrijednosti ključa, koji se svodi na: prepuštanje

bazi podataka generiranje vrijednosti ključa, korištenje GUID-a ili prepustiti generiranje vrijednosti ključa

Page 14: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

10

programerima.

4.1.4. Struktura rješenja

Strukture uzorka dizajna Identity Field ovisi uglavnom o tome koristi li se jednostavni ili složeni

primarni ključ. Slika 4.7.1. prikazuje odnos između klase i relacijske tablice za neki entitet kada bi se koristio

jednostavni ključ. U slučaju na slici, korišten je tip podatka Object, ali u praksi bi se taj tip podatka prilagodio

tipu podatka iz relacijske tablice.

Slika 4.1.1. Odnos između klase i relacijske tablice za neki entitet koji

koristi jednostavni primarni ključ

Slika 4.1.2. prikazuje slučaj kada bi se za neki entitet koristio složeni primarni ključ. U tom slučaju uvodi se

klasa Key koja postaje kompozitni dio klase entiteta.

Slika 4.1.2. Odnos između klase i relacijske tablice za neki entitet koji koristi složeni ključ

Fowler (2003:224) navodi kako bi bilo dobro nadjačati metodu equals() za klasu Key kako bi se ključevi

međusobno mogli uspoređivati prema njihovim vrijednostima, tj. nad Key objektima bilo bi dobro primijeniti

uzorak dizajna Value Object.

4.1.5. Primjer

Jednostavni primarni ključ u objektno-orijentiranom sustavu može biti obično polje u klasi entiteta.

Za složeni ključ bi se trebala kreirati posebna klasa. U ovom primjeru kreirati će se klasa primarnog ključa

koja se može koristiti i za jednostavne primarne ključeve i za složene primarne ključeve.

Takva klasa će objekte, članove primarnog ključa, spremati u polje tipa Object. Također će imati konstruktor,

metodu za dohvaćanje pojedinog člana primarnog ključa, metodu za postavljanje primarnog ključa i

primijeniti će se uzorak dizajna Value Object.

Page 15: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

11

Primjer koda 4.1.1. Klasa primarnog ključa

public class PrimaryKey {

private Object[] keyObjects;

public PrimaryKey(Object... keyObjects) {

this.keyObjects = keyObjects;

}

public Object get(int index) {

if (index >= 0 && index < keyObjects.length) return keyObjects[index];

else return null;

}

public void set(Object... keyObjects) { this.keyObjects = keyObjects; }

@Override

public boolean equals(Object obj) {

if (!(obj instanceof PrimaryKey)) return false;

PrimaryKey other = (PrimaryKey) obj;

if (this.keyObjects.length != other.keyObjects.length) return false;

for (int i = 0; i < this.keyObjects.length; i++)

if (!this.keyObjects[i].equals(other.keyObjects[i])) return false;

return true;

}

@Override

public int hashCode() {

return 47 + Arrays.deepHashCode(this.keyObjects);

}

}

4.2. Identity Map

4.2.1. Namjera

Osigurava učitavanje objekata samo jednom tako što ih se sprema u mapu, a kasnije se ti objekti

dohvaćaju iz te mape (Fowler, 2003).

4.2.2. Problem

Ako programer ne bi pazio kako aplikacija učitava podatke iz baze podataka, može doći do

preuzimanja istog podatka na više objekata (Fowler, 2003:195). To dovodi do dvije vrste problema:

1. Radna memorija računala se puni s višestrukim kopijama istog podatka.

2. Ažuriranje može biti problematično jer ako jedan objekt promjeni unutarnje stanje objekta i time

ažurira bazu podataka, ostali objekti će i dalje zadržati staro stanje.

4.2.3. Rješenje

Rješenje je prilično jednostavno: uvede se rječnik koja će držati referencu na učitani podataka iz

baze podataka. Pod rječnikom se misli apstraktni tip podatka rječnik (eng. dictionary) koji se u drugim

Page 16: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

12

programskim jezicima (npr. Java) može još zvati mapa (eng. map). Za svaku tablicu trebao bi postojati jedan

rječnik. Ključ za rječnik bi, u pravilu, bio primarni ključ tablice.

U slučaju Web aplikacija, Fowler (2003:197) navodi kako bi trebao postojati jedan Identity Map objekt po

sesiji. Ako postoji jedan Identity Map objekt za cijelu Web aplikaciju, tada spomenuti objekt treba zaštiti od

istovremenih transakcija.

4.2.4. Struktura rješenja

Za uzorak dizajna Identity Map nije zadana neka konkretna struktura rješenja. Sve što je potrebno je

uvesti rječnik unutar kojeg bi se pohranili učitani podaci iz baze podataka i prilagoditi operacija čitanja

podataka tako da:

1. provjeravaju postoji li traženi podatak, odnosno objekt, u odgovarajućem rječniku i ako postoji

vratiti referencu tog objekta,

2. ako podatak ne postoji tada se ono učitava iz baze podataka u objekt, objekt se pohrani u

odgovarajući rječnik i vraća se referenca na taj objekt.

Programer ima slobodu implementirati ovaj uzorak dizajna kako misli da je najbolje. Radi lakšeg korištenja,

možda bi bilo dobro sve bitne operacije sa rječnikom (dodavanje, dohvaćanje i brisanje) učahuriti u zasebnu

klasu. Tako bi za svaku tablicu postojao jedan objekt koji implementira uzorak dizajna Identity Map.

4.2.5. Primjer

Za primjer uzorka dizajna Identity Map pretpostaviti će se da sve klase entiteta nasljeđuju apstraktnu

klasu Entity koja sadrži polje za primarni ključ i metode za dohvaćanje i postavljanje vrijednosti primarnog

ključa. Primjer koda 4.2.1. prikazuje spomenutu apstraktnu klasu.

Primjer koda 4.2.1. Apstraktna klasa Entity

public abstract class Entity {

protected Long id;

public Long getId() { return id; }

public void setId(Long id) { this.id = id; }

}

Kako bi se implementirao uzorak Identity Map, kreirat će se generička klasa koja će primati sve tipove

podataka koji nasljeđuju klasu Entity. Ta klasa će sadržavati polje tipa Map u kojem će se spremati objekti

entiteta i imati će definirane metode za dodavanje, dohvaćanje i brisanje objekta entiteta, provjeravanje

postojanosti entiteta u mapi, čišćenje te vraćanje popisa objekata koji su filtrirani pomoću parametra tipa

Predicate. Primjer koda 4.2.2. prikazuje tu klasu.

Primjer koda 4.2.2. Generična klasa IdentityMap

public class IdentityMap<T extends Entity> {

protected Map<Long, T> entities = new HashMap<>();

public void add(T entity) {

Page 17: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

13

if (entity.getId() != null)

entities.put(entity.getId(), entity);

}

public void remove(Long id) {

entities.remove(id);

}

public boolean contains(Long id) {

return entities.containsKey(id);

}

public void clear() {

entities.clear();

}

public List<T> filter(Predicate<T> predicate) {

List<T> filteredEntities = new ArrayList<>();

entities.forEach((id, entity) -> {

if (predicate.test(entity)) {

filteredEntities.add(entity);

}

});

return filteredEntities;

}

}

Nadalje, tu klasu može naslijediti neka druga klasa koja bi specificirala s kojim tipom entiteta radi (primjer

koda 4.2.3.) ili se tip podatka može specificirati direktno tijekom instanciranja (primjer koda 4.2.4.)

Primjer koda 4.2.3. Nasljeđivanje klase IdentityMap

public class EmployeeMap extends IdentityMap<Employee> {}

Primjer koda 4.2.4. Direktna primjena klase IdentityMap

IdentityMap<Employee> employeeMap = new IdentityMap<>();

U bilo kojem slučaju, potrebno je operacije čitanja podatka izmijeniti tako da prvo provjeri postoji li već

traženi objekt u mapi te vratiti instancu tog objekta ako postoji.

Page 18: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

14

4.3. Repository

4.3.1. Namjera

Služi kao posrednik između poslovnog sloja i sloja zaslužnog za preslikavanje podataka (eng. data

mapping layer) tako da se pristupa objektima preko sučelja slično onome koji se koristi za kolekcije (Fowler,

2003:322).

4.3.2. Problem

Fowlerov (2003) opis problema kojeg rješava uzorak dizajna Repository je, prema vlastitom

mišljenju, dosta zbunjujući. Problem se svodi na potrebu za dodavanje dodatnog sloja apstrakcije koji je

zaslužan za ispitivanje (eng. querying) podataka i taj se sloj obično dodaje nad slojem zaslužnim za

preslikavanje podataka (Fowler, 2003:322). Drugim riječima, ovaj uzorak dizajna dobro dođe ako se želi

apstrahirati rad s podacima (dodavanje, brisanje, pretraživanje i ažuriranje) tako da izgleda kao da se radi s

kolekcijom u objektno-orijentiranom programskom jeziku.

4.3.3. Rješenje

Rješenje je napraviti posrednički objekt koji će koristiti objekte zaslužne za preslikavanje podataka

kako bi glumio kolekciju objekata u objektno-orijentiranom sustavu (Fowler, 2003:322). Ovaj uzorak dizajna

sastoji se od nekoliko drugih uzoraka dizajna:

• uzoraka dizajna za preslikavanje podataka između baze podataka i objekata (npr. Data Mapper),

• uzorka dizajna za izgradnju upita kojima će se pretraživati određeni podaci (npr. Query Object).

Uzorak dizajna za izgradnju upita nije potreban, ali dodaje određenu fleksibilnost uzorku dizajna Repository

i, kako navodi Fowler (2003:323), dodaje veliku mjeru korisnosti za ORM sloj. Također, ovaj uzorak dizajna

se može implementirati tako da radi s više različitih baza podataka, odnosno izvora podataka (Fowler,

2003:324). Pod pretpostavkom da implementacija ovog uzorka dizajna ima različite konfiguracije za rad s

vanjskim izvorima podataka, jedan od tih izvora podataka može biti relacijska baza podataka poput

PostgreSQL-a, druga konfiguracija može biti NoSQL baza podataka poput MongoDB-a, treća konfiguracija

može biti opet relacijska baza podataka koja koristi drugačiju sintaksu za određene operacije (npr. definiranje

primarnog ključa koji se sam od sebe inkrementira), itd.

4.3.4. Struktura rješenja

Fowler (2003) u svom opisu uzorka dizajna Repository nije dao konkretni dijagram klasa za prikaz

strukture ovog uzorka već je opisao njegovo ponašanje putem dijagrama sekvence. Ovdje će se ipak koristiti

dijagram klasa i za svaku komponentu tog dijagrama objasniti će se što ona radi. Slika 4.3.1. prikazuje

dijagram klasa za uzorak dizajna Repository.

Page 19: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

15

Slika 4.3.1. Dijagram klasa za uzorak dizajna Repository

Elementi prikazani na slici 4.3.1. imaju sljedeće uloge:

• AbstractMapper

◦ Sučelje ili apstraktna klasa koja implementira uzorak dizajna Data Mapper i koristiti će se za

provođenje operacija kreiranja, čitanja, ažuriranja i brisanja podataka iz baze podataka.

• Repository

◦ Sučelje ili apstraktna klasa koja će pomoću AbstractMapper i Criteria raditi s bazom podataka,

a pritom će korisniku izgledati kao da koristi običnu objektno-orijentiranu kolekciju.

• ConcreteRepository

◦ Implementacija sučelja Repository. Svaka implementacija koristi zasebnu implementaciju

sučelja AbstractMapper za preslikavanje podataka. Također, svaka od implementacija radi na

zasebnim objektom koji predstavlja podataka iz odgovarajuće tablice u bazi podataka.

Fowler (2003:324) navodi korištenje specijaliziranih objekata koji implementiraju strategije kojima bi se

proširila funkcionalnost uzorka dizajna Repository. Ti objekti su zapravo specifične implementacije uzorka

dizajna Strategy kojeg opisuju Gamma et al. (1995). Na taj način implementacija uzorka dizajna Repository

ne bi bila ograničena na samo jednu bazu podataka, tj. izvor podataka, nego više njih (Fowler, 2003:324).

Npr. jedna implementacija sučelja Strategy mogla bi se odnositi na PostgreSQL bazu podataka,a neka druga

implementacija istog sučelja bi se mogla odnositi na neku NoSQL bazu podataka poput MongoDB. Slika

4.3.2. prikazuje proširenje dijagrama klase sa slike 4.3.1. tako da koristi uzorak dizajna Strategy.

Slika 4.3.2. Dijagram klasa uzorka dizajna Repository koja koristi Strategy

Page 20: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

16

4.3.5. Primjer

Ovaj primjer uzorka dizajna Repository telmeljiti će se na tome da će sve klase entiteta nasljeđivati

apstraktnu klasu Entity. Apstraktna klasa Entity, prikazana na slici 4.3.1., sadrži polje koje predstavlja

vrijednost primarnog ključa te metode za dohvaćanje i postavljanje tog polja. Ta klasa će se koristiti kako bi

se implementacije uzorka dizajna Repository ograničio da koristi samo objekte čije klase nasljeđuju Entity.

Primjer koda 4.3.1. Apstraktna klasa Entity

public abstract class Entity {

protected long id;

public long getID() { return id; }

public void setID(long id) { this.id = id; }

}

Glavna ideja ovog primjera je kreirati osnovnu Repository klasu koja će koristiti objekt uzorka dizajna Data

Mapper i objekt uzorka dizajna Identity Map. Ta klasa bi učahurila operacije s tim objektima kako bi se

formirao mali podsustav koji bi omogućavao osnovno brisanje i ažuriranje tih podataka, ali bi tijekom čitanja

dohvaćene podatke pohranio kako bi ti isti podaci ne bi čitali iz baze podataka već izravno iz memorije.

Primjer koda 4.3.2. pokazuje apstraktnu i generičku klasu Repository.

Primjer koda 4.3.1. Apstraktna klasa Entity

public abstract class Repository<T extends Entity> {

protected AbstractMapper<T> mapper;

protected IdentityMap<T> map;

public Repository(AbstractMapper<T> mapper, IdentityMap<T> map) {

this.mapper = mapper;

this.map = map;

}

public void add(T entity) {

mapper.create(entity);

map.add(entity);

}

public void remove(T entity) {

mapper.delete(entity);

map.remove(entity);

}

public void update(T entity) {

mapper.update(entity);

}

public T get(long id) {

if (map.contains(id)) {

return map.get(id);

}

T entity = mapper.find(id);

map.add(entity);

return entity;

Page 21: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

17

}

public List<T> getAll() {

List<T> entities = mapper.findAll();

for (int i = 0; i < entities.size(); i++) {

T currentEntity = entities.get(i);

if (map.contains(currentEntity.getId()) {

entities.set(i, map.get(currentEntity.getId();

} else {

map.add(currentEntity);

}

}

return entities;

}

}

Nadalje, kreirana klasa Repository bi se proširivala putem podklasa koji bi specificirali s kojim tipom entiteta

bi radili (primjer koda 4.3.3.).

Primjer koda 4.3.3. Nasljeđivanje klase Repository

public class CustomerRepository extends Repository<Customer> {

public CustomerRepository() {

super(new CustomerMapper(), new IdentityMap<Customer>());

}

}

4.4. Ostali uzorci dizajna

U ovom potpoglvalju, ukratko će se opisati namjena ostalih uzoraka dizajna koji bi bili primjereni

za upotrebu u podatkovnom sloju. Za razliku od prethodna tri opisana uzorka dizajna, uzorci dizajna u ovom

potpoglavlju neće koristiti predložak za opis koji je definiran u 3.2. Struktura korištenog predloška.

4.4.1. Association Table Mapping

Association Table Mapping (Fowler, 2003:248) je uzorak dizajna koji se primjenjuje na bazu

podataka, odnosno na njenu strukturu. Ovaj uzorak dizajna rješava problem pohrane veze više-više između

dva objekta u obliku relacijske tablice. Rješenje je uvođenje dodatne tablice u bazu podataka koja se sastoji

od vanjskih ključa koji referenciraju relacijske tablice koji sudjeluju u vezi više-više.

4.4.2. Foreign Key Mapping

Foreign Key Mapping (Fowler, 2003:236) se također primjenjuje na bazu podataka i ono služi za

preslikavanje referenci između objekata kao vanjski ključ u relacijskim tablicama. Ovaj uzorak dizajna je

primjenjiv ako su objekti u vezi jedan-jedan ili jedan-više. U slučaju veze više-više primjenjuje se uzorak

dizajna Association Table Mapping.

4.4.3. Class Table Inheritance

Class Table Inheritance (Fowler, 2003:285) se primjenjuje u slučajevima kada se koncept

nasljeđivanja klasa u objektno-orijentiranom sustavu želi implementirati za relacijske baze podataka. Za

svaku pojedinačnu klasu (i apstraktne i konkretne) u hijerarhiji nasljeđivanja se kreira posebna tablica i svaka

Page 22: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

18

tablica će imati samo one stupce koji odgovaraju poljima koji su definirano samo za tu klasu.

4.4.4. Concrete Table Inheritance

Concrete Table Inheritance (Fowler, 2003:293) je varijacija na uzorak dizajna Class Table

Inheritance u kojemu se kreira tablica za svaku konkretnu klasu u hijerarhiji nasljeđivanja. U tom slučaju,

svaka podređena tablica će također imati one stupce koji su definirani u nadređenoj tablici.

4.4.5. Single Table Inheritance

Single Table Inheritance (Fowler, 2003:278) je varijacija na prethodne dva Table Inheritance uzoraka

dizajna u kojemu postoji jedna, jedina, relacijska tablica za cijelu hijerarhiju klasa.

4.4.6. Dependent Mapping

Dependent Mapping (Fowler, 2003:262) omogućuje jednoj klasi (vlasniku) preslikavanje podataka

za klasu koja ovisi o njoj. Ovaj uzorak dizajna se koristi samo ako su objekti ovisne klase strogo vezani za

jednog vlasnika, odnosno ako bi se obrisao podatak o vlasniku onda se gube i ovisni podaci.

4.4.7. Metadata Mapping

Metadata Mapping (Fowler, 2003:306) drži detalje o preslikavanju entiteta između objekta i

relacijske tablice u nekom metapodatku. Metapodatak može biti posebna datoteka, koju aplikacija učita kako

bi saznala kako provesti preslikavanje, ili se mogu koristiti anotacije te bi aplikacija očitala detalje

preslikavanja pomoću refleksije. Ovaj uzorak dizajna se može koristiti zajedno s uzorcima za preslikavanja

podataka, a također služi kao temelj za fleksibilan ORM sustav.

4.4.8. Serialized LOB

Serialized LOB (Fowler, 2003:272) služi za preslikavanje strukture podataka nekog objekta, ili graf

objekata, njegovom serijalizacijom u jedan veliki objekt (eng. large object; LOB) koji se pohranjuje u jedno

polje u bazi podataka. Može koristiti serijalizacija objekata koju omogućava programski jezik, tada s graf

objekata preslikava kao BLOB (Binary Large Object), ili se može koristiti mehanizmi koji bi pretvorili graf

objekta u tekstualni oblik (npr. u XML), čime bi se graf objekta preslikavao kao CLOB (Character Large

Object).

4.4.9. Embedded Value

Embedded Value (Fowler, 2003:268) služi za preslikavanje jednog objekta, koji se postoji kao polje

u objektu entiteta, u dva ili više polja u relacijskoj tablici. Radi se o malim objektima koji imaju smisla

postojati u objektno-orijentiranom sustavu, ali u bazi podataka bilo bi suludo im dodijeliti vlastitu tablicu.

4.4.10. Value Object

Value Object (Fowler, 2003:486) je objekt čija se jednakost ne temelji na identitetu već na temelju

vrijednosti. Najjednostavniji primjer takvog objekta bi bilo objekti koji predstavljaju nekakav novčani iznos.

Ovaj uzorak dizajna se, u programskom jeziku Java, provodi nadjačavanjem metoda equals() i hashCode()

tako da se za usporedbu koriste polja od kojih se Value Object objekt sastoji.

Page 23: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

19

4.4.11. Lazy Load

Lazy Load (Fowler, 2003:200) se koristi kada se želi odgoditi učitavanje određenih (ili svih)

podataka nekog objekta tek kada budu potrebni.

Page 24: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

20

5. Uzorci dizajna za rad s bazom podataka

U ovom poglavlju opisati će se uzorci dizajna koji bi se primijenili za rad s bazom podataka i koji bi

ga u neku ruku pojednostavili. Pod radom s bazom podataka misli se na komunikaciju između aplikacije i

baze podataka. Općeniti postupak rada s bazom podataka (koji je više puta spomenut u ovom radu) je:

kreiranje veze na bazu podataka, provođenje SQL upita kroz tu vezu i, ovisno o vrsti provedene operacije,

učitavanje podataka ili provjera je li upit uspješno proveden.

Uzorci dizajna u ovom poglavlju imaju različite namjene što se tiče rada s bazom podataka. Na primjer, jedan

uzorak dizajna predstavlja objekt koji bi učahurio komunikaciju s određenom tablicom u relacijskoj bazi

podataka (Table Data Gateway), drugi skup uzoraka dizajna koristi se za preslikavanje podataka iz baze

podataka u objekt i obratno (Active Record, Data Mapper, Row Data Gateway).

Nadalje u ovom poglavlju, opisati će se uzorci dizajna primjenjivi za rad s bazom podataka. Kao što je

korišteno u poglavlju 4. Uzorci dizajna za podatkovni sloj, i za uzorke dizajna u ovom poglavlju će se koristiti

predložak za njihov opis koji je definiran u poglavlju 3. Predložak za opis uzoraka dizajna.

Page 25: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

21

5.1. Active Record

5.1.1. Namjera

Predstavlja objekt koji sadrži vrijednosti jednog retka iz relacijske tablice ili pogleda u bazi podataka,

učahuruje način na koji objekt pristupa bazi podataka i sadrži dodatnu funkcionalnost koja je vezana za tu

specifičnu tablicu u bazi podataka (Fowler, 2003:160).

5.1.2. Problem

Kada je potrebno programski učitati podatke iz baze podataka, potrebno je kreirati vezu prema bazi

podataka (ako već ne postoji globalni pristup prema objektu koji drži vezu prema bazi podataka), napisati

SQL upit i pozvati metodu iz objekta za vezu prema bazi podataka koji će vratiti rezultat upita kao objekt

klase ResultSet. Nakon toga, prolazi se kroz svaki redak iz spomenutog objekta klase ResultSet i podaci se

učitavaju u jedan ili više drugih objekata. To je standardni, programski, postupak učitavanja podataka iz baze

podataka. Takav postupak može zauzimati malo ili veliki broj linija programskog koda, ovisno o

kompleksnosti relacijske tablice iz koje se žele učitati podaci. Naravno, jednokratno to ne predstavlja

preveliki problem, ali ako se podaci učitavaju u različitim dijelovima programa onda je potrebno ponovno

napisati (ili kopirati) takav kod.

No, opisani primjeri se odnosi samo na učitavanje podataka iz relacijske tablice. Tu postoje još operacije

kreiranja novog zapisa te ažuriranje ili brisanje postojećeg zapisa iz baze podataka.

5.1.3. Rješenje

Rješenje su klase čiji objekti bi sadržavali podatke iz odgovarajućih relacijskih tablica i koji bi sami

bili zaslužni za kreiranje, učitavanje, ažuriranje i brisanje podataka u bazu podataka. Svako polje u klasi treba

odgovarati stupcu iz odgovarajuće relacijske tablice u bazi podataka (Fowler, 2003:160).

Fowler (2003:161) navodi kako Active Record klasa sadrži sljedeće metode:

• metode za dohvaćanje (getter) i postavljanje (setter) vrijednosti polja u objektu,

• metoda koja kreira instancu Activer Record klase iz reda koji se očita iz rezultata SQL upita,

• metoda koja kreira instancu za kasnije dodavanje u relacijsku tablicu,

• metoda za ažuriranje baze podataka i dodavanje podataka iz Active Record objekta,

• statične metode kojima se traži i dohvaća specifičan red iz relacijske tablice i vraća u obliku instance

Active Record objekta,

• dodatna poslovna logika po potrebi.

Prema vlastitom mišljenju, metode za pretraživanje i dohvaćanje specifičnog zapisa ne trebaju nužno biti

statične metode, već mogu biti obične metode koje pune pozivajući objekt s dohvaćenim podacima. No, to

može biti stvar dizajna ili osobne preferense.

Naravno, uzorak dizajna Active Record sadrži i određena ograničenja. Jedno od tih ograničenja je što je jedna

Page 26: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

22

Active Record klasa vezana za jednu relacijsku tablicu ili pogled u bazi podataka (Fowler, 2003:161-162).

Drugo ograničenje koje Fowler (2003:162) ističe je povezanost između dizajna u bazi podataka i objektnog

dizajna. Ako se promjeni shema relacijske tablice u bazi podataka, tada se treba promijeniti i prikladna Active

Record klasa.

5.1.4. Struktura rješenja

Fowler (2003) u svojem opisu uzorka dizajna Active Record nije dao konkretnu strukturu rješenja.

No, kao što je spomenuto, Active Record klasa po svojoj strukturi treba odgovarati odabranoj relacijskoj

tablici i treba implementirati CRUD2 operacije u koje su također učahuren način na koji će objekt pristupiti

bazi podataka.

Zato, umjesto prikaza apstraktne strukture rješenje, kako se to obično radi u knjizi od Gamma et al. (1995),

prikazat će se jednostavni primjer strukture rješenje za uzorak dizajna Active Record. Slika 5.1.1. prikazuje

relacijska tablicu entity i strukturu klase Entity koja je povezana s tom relacijskom tablicom.

Svaki stupac, odnosno atribut, relacijske tablice ima odgovarajuće polje u Active Record klasi. Tim poljima

se pristupa pomoću odgovarajućih metoda za dohvat vrijednosti polja (getter metodama) i ta se polja mogu

promijeniti metodama za postavljanje vrijednosti polja (setter metodama). Ostale metode služe za kreiranje,

čitanje, ažuriranje i brisanje zapisa iz baze podataka. Metode koje su definirane za klasu odgovaraju

metodama koje je opisao Fowler (2003:161) za Active Record klasu, ali bez dodatne poslovne logike koja se

može lagano dodati po potrebi.

2C – kreiranje (create), R – čitanje (read), U – ažuriranje (update), D – brisanje (delete)

Page 27: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

23

Slika 5.1.1. Relacijska tablica "entity" i Active Record klasa "Entity"

povezana s tom tablicom

5.1.5. Primjer

U ovom primjeru pretpostaviti će se da sve klase entiteta trebaju nasljeđivati apstraktnu klasu Entity

prikazana u primjeru koda 5.1.1.

Primjer koda 5.1.1. Apstraktna klasa Entity

public abstract class Entity { protected long id; public long getId() { return id; } public void setId(long id) { this.id = id; } }

Sljedeće, kreirati će se apstraktna generička klasa ActiveRecord koja će implementirati temeljni mehanizam

za vlastito preslikavanje objekata. Određeni dijelovi tog mehanizma pozivati će apstraktne metode koje

moraju biti implementirane putem podklasa. Također, ta apstraktna klasa će nasljeđivati apstraktnu klasu

Entity tako da svaka klasa koja naslijedi ActiveRecord će biti prepoznata i kao klasa entiteta.

Prvo, implementirati će se metode za kreiranje novog zapisa u bazu podataka, koja je prikazana u primjeru

koda 5.1.2. Metoda kreira (ili dohvaća) vezu prema bazi podataka, priprema SQL upit za izvršavanje,

postavlja parametre pripremljenog upita te izvodi upit. Nakon upita metoda postavlja ID novog zapisa u

objekt pozivajući metodu setId() iz klase Entity. Metoda također poziva apstraktnu metodu

Page 28: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

24

getCreateStatement() da dohvati SQL upit kojeg implementira podklasa i apstraktnu metodu

setCreateStatementParameters() za postavljanje parametara pripremljenog upita.

Primjer koda 5.1.2. Metode za kreiranje novog zapisa u bazu podataka

public abstract class ActiveRecord<T> extends Entity { public void create() { try (Connection conn = createConnection(); PreparedStatement ps = conn.prepareStatement( getCreateStatement(), Statement.RETURN_GENERATED_KEYS)) { setCreateStatementParameters(ps); ps.execute(); try (ResultSet rs = ps.getGeneratedKeys()) { if (rs.next()) { setId(rs.getLong(1)); } } } catch (SQLException ex) { System.out.println("Unable to create entity."); ex.printStackTrace(System.out); } } protected abstract String getCreateStatement(); protected abstract void setCreateStatementParameters(PreparedStatement ps) throws SQLException; // ... }

Sljedeće, napraviti će se metoda za ažuriranje podatka za bazu podataka. Metoda izgleda slično metodi za

kreiranje novog zapisa, jedine razlike su pozivanje druge apstraktne metode koja dohvaća SQL upit za

pripremu i pozivanje druge metode za postavljanje parametara pripremljenog upita. Metoda za ažuriranje

prikazana je u primjeru koda 5.1.3.

Primjer koda 5.1.3. Metoda za ažuriranje podatka za bazu podataka

public abstract class ActiveRecord<T> extends Entity { // ... public void update() { try (Connection conn = createConnection(); PreparedStatement ps = conn.prepareStatement(getUpdateStatement())) { setUpdateStatementParameters(ps); ps.execute(); } catch (SQLException ex) { System.out.println("Unable to update entity."); ex.printStackTrace(System.out); } } protected abstract String getUpdateStatement(); protected abstract void setUpdateStatementParameters(PreparedStatement ps) throws SQLException; // ... }

Page 29: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

25

Zatim, kreirati će se metoda za brisanje podatka u bazi podataka, prikazana u primjeru koda 5.1.4. Metoda je

slična prethodnim dvjema metodama, osim što poziva drugu metodu za dohvaćanje SQL upita za pripremu i

poziva drugu metodu za postavljanje parametara pripremljenog upita.

Primjer koda 5.1.4. Metoda za brisanje podatka iz baze podataka

public abstract class ActiveRecord<T> extends Entity { // ... public void delete() { try (Connection conn = createConnection(); PreparedStatement ps = conn.prepareStatement(getDeleteStatement())) { setDeleteStatementParameters(ps); ps.execute(); } catch (SQLException ex) { System.out.println("Unable to delete entity."); ex.printStackTrace(System.out); } } protected abstract String getDeleteStatement(); protected abstract void setDeleteStatementParameters(PreparedStatement ps) throws SQLException; // ... }

Ostale su još metode za učitavanje podatka iz baze podataka u Active Record objekt. Kreirati će se dvije

metode: jedna koja učitava podatak na temelju proslijeđenog ID-a i druga koja učitava podatak iz objekta

ResultSet. Prva metoda se također poslužuje drugom metodom. Druga metoda prepušta podklasama da

implementiraju način učitavanja podataka iz objekta ResultSet. Primjer koda 5.1.5. prikazuje metode za

učitavanje podataka.

Primjer koda 5.1.5. Metoda za učitavanje podataka u objekt

public abstract class ActiveRecord<T> extends Entity { // ... public void loadById(long id) { try (Connection conn = createConnection(); PreparedStatement ps = conn.prepareStatement( getSelectByIdStatement())) { setSelectByIdStatementParameters(ps, id); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { loadFromResultSet(rs); } } } catch (SQLException ex) { System.out.println("Unable to load entity by ID."); ex.printStackTrace(System.out); } } protected abstract String getSelectByIdStatement(); protected abstract void setSelectByIdStatementParameters(

Page 30: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

26

PreparedStatement ps, long id) throws SQLException; public void loadFromResultSet(ResultSet rs) { try { doLoadFromResultSet(rs); } catch (SQLException ex) { System.out.println("Unable to load entity from result set."); ex.printStackTrace(System.out); } } protected abstract void doLoadFromResultSet(ResultSet rs) throws SQLException; // ... }

Može se uočiti u prethodnim primjerima koda korištenje metode createConnection() kako bi se kreirala

objekt veze prema bazi podataka. Radi konzistentnosti, primjer 5.1.6. pokazuje moguću implementaciju te

metode.

Primjer koda 5.1.6.Implementacija apstraktne klase ActiveRecord u klasi License

public class ActiveRecord<T> extends Entity { // ... protected Connection createConnection() { try { Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance(); return DriverManager.getConnection( "jdbc:derby://localhost:1527/mydb", "username", "password"); } catch (Exception ex) { throw new RuntimeException("Unable to connect to the database."); } } }

Time je dovršena apstraktna generička klasa ActiveRecord i može se početi implementirati konkretne klase

entiteta. Primjer koda 5.1.6. prikazuje implementaciju napravljene apstraktne klase za entitet License koji se

sastoji od polja ID (definiran u apstraktnoj klasi Entity), naziva license i njenog opisa.

Primjer koda 5.1.7.Implementacija apstraktne klase ActiveRecord u klasi License

public class License extends ActiveRecord<License> { private static final String CREATE_STATEMENT = "INSERT INTO license VALUES (DEFAULT, ?, ?)"; private static final String UPDATE_STATEMENT = "UPDATE license SET name=?, description=? WHERE id=?"; private static final String DELETE_STATEMENT = "DELETE FROM license WHERE id=?"; private static final String SELECT_BY_ID_STATEMENT = "SELECT * FROM license WHERE id=?";

Page 31: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

27

private String name; private String description; public String getName() { return name; } public String getDescription() { return description; } public void setName(String name) { this.name = name; } public void setDescription(String description) { this.description = description; } @Override protected String getCreateStatement() { return CREATE_STATEMENT; } @Override protected String getUpdateStatement() { return UPDATE_STATEMENT; } @Override protected String getDeleteStatement() { return DELETE_STATEMENT; } @Override protected String getSelectByIdStatement() { return SELECT_BY_ID_STATEMENT; } @Override protected void setCreateStatementParameters(PreparedStatement ps) throws SQLException { ps.setString(1, getName()); ps.setString(2, getDescription()); } @Override protected void setUpdateStatementParameters(PreparedStatement ps) throws SQLException { ps.setString(1, getName()); ps.setString(2, getDescription()); ps.setLong(3, getId()); } @Override protected void setDeleteStatementParameters(PreparedStatement ps) throws SQLException { ps.setLong(1, getId()); } @Override protected void setSelectByIdStatementParameters(PreparedStatement ps, long id) throws SQLException {

Page 32: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

28

ps.setLong(1, id); } @Override protected void doLoadFromResultSet(ResultSet rs) throws SQLException { setId(rs.getLong("id")); setName(rs.getString("name")); setDescription(rs.getString("description")); } }

Nadalje, u klasu License mogu se dodavati dodatne metode po želji. Također se i klasa License smije proširiti

ako bi se htjele napraviti dodatne izmjene ili proširenja.

Page 33: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

29

5.2. Data Mapper

5.2.1. Namjera

Predstavlja sloj objekata za preslikavanje podataka između objekata i pripadajućih relacijskih tablica

u bazi podataka, i to tako da su objekti i baza podataka međusobno neovisni i oboje je također neovisno o

objektu preslikavanja (Fowler, 2003:165).

5.2.2. Problem

Opis problema za uzorak dizajna Active Record se također može koristiti kao problem kojeg rješava

ovaj uzorak dizajna. Jedina iznimka je zahtjev gdje su objekti i relacijske tablice međusobno neovisni,

odnosno objekt ne treba znati za postojanost relacijska tablice i relacijska tablice ne treba znati za postojanost

objekta.

Ukratko rečeno, problem vezan za ovaj uzorak dizajna je kako pojednostaviti preslikavanje podataka između

objekta i relacijske tablice, ali tako da jedno ne zna za drugo. Fowler (2003:165) takvu situaciju naziva

odvajanje domene od izvora podataka.

5.2.3. Rješenje

Fowler (2003:165-166) govori o dodavanju razine koja je zaslužna za preslikavanje podataka između

objekata i relacijskih tablica. Na tu razinu se može gledati kao skupina objekata koji su zaslužni za

preslikavanje podataka između pripadajućih objekata i relacijskih tablica. Objekt za preslikavanje poznaje

objekt i relacijsku tablicu s kojima radi, dok isti objekt i tablica ne znaju za objekt za preslikavanje.

Active Record i Data Mapper imaju istu namjenu, ali različite filozofije. Kod uzorka dizajna Active Record

objekti su sami zaslužni za preslikavanje podataka iz odgovarajuće relacijske tablice u sebe i obratno. Kod

uzorka dizajna Data Mapper za preslikavanje podataka između objekta i relacijske tablice odgovoran je

poseban objekt.

5.2.4. Struktura rješenja

Slika 5.2.1. pokazuje primjer strukture rješenja za uzorak dizajna Data Mapper. Za ovaj primjer

zamišljeno je da apstraktna klasa DataMapper definira osnovno ponašanje za kreiranje, čitanje, ažuriranje i

brisanje zapisa, a to ponašanje bi se proširilo kroz njene podklase.

Takvo ponašanje je implementacija uzorka dizajna Template Method, kojeg su opisali Gamma et al. (1995),

a ono je savršen uzorak dizajna s kojim bi se Data Mapper učinio proširivim i fleksibilnim. No, DataMapper

se također može definirati kao sučelje, tada bi podklase u potpunosti implementirale ponašanje za uzorak

Data Mapper.

Page 34: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

30

Slika 5.2.1. Primjer strukture rješenja za Data Mapper

5.2.5. Primjer

Primjer Data Mapper uzorka dizajna koji će se ovdje obraditi se također primjenjuje u aplikaciji u

sklopu ovog rada. Koristi se već spomenuti dogovor u kojemu sve klase entiteta nasljeđuju apstraktnu klasu

Entity prikazanoj u primjeru koda 5.2.1.

Primjer koda 5.2.1. Apstraktna klasa Entity

public abstract class Entity { protected long id; public long getId() { return id; } public void setId() { this.id = id; } }

Definirati će se apstraktna i generička klasa DataMapper koja će implementirati temeljne mehanizme

preslikavanja podataka. čije podklase će biti ograničene samo na one tipove podataka koji nasljeđuju klasu

Entity. Također, Data Mapper u ovom primjeru će koristiti Identity Map uzorak kako bi se izbjeglo

instanciranje objekata entiteta s istim podacima, odnosno kako bi se izbjegli duplikati.

Metode koje će implementirati preslikavanja koristite metodu createConnection(), prikazana u primjeru

koda 5.2.2., kojom se uspostavlja veza prema bazi podataka.

Primjer koda 5.2.2. Apstraktna klasa Entity

public abstract class DataMapper<T extends Entity> { // ... protected Connection createConnection() { try { ServletContext sc = ApplicationListener.getServletContext(); DataSource dataSource = (DataSource) sc.getAttribute("DerbyDB"); return dataSource.getConnection(); } catch (SQLException ex) { ex.printStackTrace(System.out); throw new RuntimeException(ex); } } // ... }

Page 35: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

31

Prvo, definirati će se metode za kreiranje zapisa u bazu podataka. Njen programski kod je prikazan u primjeru

koda 5.2.3. Metoda će biti slična metodi za kreiranje zapisa u primjeru Active Record uzorka, osim sljedećeg:

• metoda prima objekt entiteta, koji se želi kreirati u bazi podataka, kao parametar,

• metoda poziva zaštićenu metodu doCreate() koja vrši kreiranje.

Razlog zašto metoda za kreiranje zapisa poziva drugu metodu koja vrši kreiranje je zbog mogućnosti

proširenja tih metoda bude nadjačavanja. Ako se originalna metoda proširi nadjačavanjem, ono neće moći

izvršiti dodatne operacije s istim vezom prema bazi podataka. Ako se metoda doCreate() proširi

nadjačavanjem, dodatne operacije mogu koristiti istu vezu prema bazi podataka koja je korištena za kreiranje.

Na takav način i metode za ažuriranje i brisanje svoje konkretne operacije pozivaju iz zaštićenih metoda.

Primjer koda 5.2.3. Metoda za kreiranje zapisa

public abstract class DataMapper<T extends Entity> { public void create(T entity) { try (Connection conn = createConnection()) { doCreate(conn, entity); map().add(entity); } catch (SQLException ex) { System.out.println("Unable to create entity (" + getClass().getSimpleName() + "): " + ex.getMessage()); ex.printStackTrace(System.out); } } protected void doCreate(Connection conn, T entity) throws SQLException { try (PreparedStatement ps = conn.prepareStatement( createStatement(), Statement.RETURN_GENERATED_KEYS)) { setCreateStatementParameters(ps, entity); ps.execute(); try (ResultSet rs = ps.getGeneratedKeys()) { rs.next(); entity.setId(rs.getLong(1)); } } } // ... }

Zatim, metoda za ažuriranje zapisa je definirana kao u primjeru koda 5.2.4.

Primjer koda 5.2.4. Metoda za ažuriranje zapisa

public abstract class DataMapper<T extends Entity> { // ... public void update(T entity) { try (Connection conn = createConnection()) { doUpdate(conn, entity); } catch (SQLException ex) { System.out.println("Unable to update entity (" + getClass().getSimpleName() + "): " + ex.getMessage());

Page 36: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

32

ex.printStackTrace(System.out); } } protected void doUpdate(Connection conn, T entity) throws SQLException { try (PreparedStatement ps = conn.prepareStatement(updateStatement())) { setUpdateStatementParameters(ps, entity); ps.execute(); } } // ... }

Metoda za brisanje zapisa definirana je i prikazana u slici 5.2.5.

Primjer koda 5.2.5. Metoda za brisanje zapisa

public abstract class DataMapper<T extends Entity> { // ... public void delete(T entity) { try (Connection conn = createConnection()) { doDelete(conn, entity); map().remove(entity.getId()); } catch (SQLException ex) { System.out.println("Unable to delete entity (" + getClass().getSimpleName() + "): " + ex.getMessage()); ex.printStackTrace(System.out); } } protected void doDelete(Connection conn, T entity) throws SQLException { try (PreparedStatement ps = conn.prepareStatement(deleteStatement())) { setDeleteStatementParameters(ps, entity); ps.execute(); } } // ... }

Metoda za učitavanje podataka iz objekta ResultSet prvo provjerava postoji li ID dohvaćenog podatka u

Identity Map objektu. Ako postoji, vraća taj objekt. Ako ne postoji, poziva metodu doLoad() koju treba

implementirati u podklasi. Metoda je prikazana u primjeru koda 5.2.6.

Primjer koda 5.2.6. Metoda za učitavanje zapisa iz ResultSet objekta

public abstract class DataMapper<T extends Entity> { // ... public T load(ResultSet rs) { try { long id = rs.getLong("id"); if (map().contains(id)) { return map().get(id); } return doLoad(rs); } catch (SQLException ex) { System.out.println("Unable to load entity ("

Page 37: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

33

+ getClass().getSimpleName() + "): " + ex.getMessage()); ex.printStackTrace(System.out); return null; } } protected abstract T doLoad(ResultSet rs) throws SQLException; // ... }

Sljedeće, definirati će dvije metode za čitanje podataka: jednu koja očitava samo jedan podatak na temelju

proslijeđenog ID-a u parametru i druga koja očitava sve podatke iz relacijske tablice. Prva metoda na početku

provjerava postoji li objekt s traženim ID-em u Identity Map objektu. Ako postoji, dohvaća i vraća taj objekt.

Obje metode koriste metodu load() kako bi konstruirale konkretni objekt entiteta. Metode za čitanje prikazane

su u primjeru koda 5.2.7.

Primjer koda 5.2.7. Metode za čitanje zapisa

public abstract class DataMapper<T extends Entity> { // ... public T find(long id) { if (map().contains(id)) { return map().get(id); } try (Connection conn = createConnection(); PreparedStatement ps = conn.prepareStatement(findStatement())) { setFindStatementParameters(ps, id); ResultSet rs = ps.executeQuery(); if (rs.next()) { T entity = load(rs); return entity; } else { return null; } } catch (SQLException ex) { System.out.println("Unable to find entity (" + getClass().getSimpleName() + "): " + ex.getMessage()); ex.printStackTrace(System.out); return null; } } public List<T> findAll() { List<T> entities = new ArrayList<>(); try (Connection conn = createConnection(); PreparedStatement ps = conn.prepareStatement(findAllStatement()); ResultSet rs = ps.executeQuery()) { while (rs.next()) { T entity = load(rs); entities.add(entity); } } catch (SQLException ex) { System.out.println("Unable to find all entities (" + getClass().getSimpleName() + "): " + ex.getMessage()); ex.printStackTrace(System.out); } return entities; }

Page 38: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

34

// ... }

Primjer koda 5.2.8. sadrži ostale apstraktne metode koje podklase moraju implementirati kako bi se mogli

kreirati konkretni objekti za preslikavanje.

Primjer koda 5.2.8. Metode za čitanje zapisa

public abstract class DataMapper<T extends Entity> { // ... protected abstract IdentityMap<T> map(); protected abstract String createStatement(); protected abstract String updateStatement(); protected abstract String deleteStatement(); protected abstract String findStatement(); protected abstract String findAllStatement(); protected abstract void setCreateStatementParameters( PreparedStatement ps, T entity) throws SQLException; protected abstract void setUpdateStatementParameters( PreparedStatement ps, T entity) throws SQLException; protected abstract void setDeleteStatementParameters( PreparedStatement ps, T entity) throws SQLException; protected abstract void setFindStatementParameters( PreparedStatement ps, long id) throws SQLException; }

Time je završena apstraktna generička klasa DataMapper. Sve što ostaje je implementirati je putem podklasa.

Page 39: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

35

5.3. Row Data Gateway

5.3.1. Namjera

Objekt koji učahuruje vezu prema samo jednom zapisu u bazi podataka i za svaki zapis postoji jedna

instanca tog objekta (Fowler, 2003:152).

5.3.2. Problem

Problem koji rješava ovaj uzorak dizajna je isti kao i problem kojeg rješava uzorak dizajna Active

Record: problem višestrukog pisanja koda za povezivanje na bazu podataka za provođenje različitih SQL

upita.

5.3.3. Rješenje

Rješenje je kreirati objekte čija objektna struktura odgovara strukturi pojedinačnog zapisa u bazi

podataka (Fowler, 2003:152). Ti objekti su sami zaslužni za provođenje operacija nad bazom podataka poput

kreiranja, ažuriranja, čitanja i brisanja, a način kako se provode te operacije su učahurene u odgovarajuće

metode.

Može se uočiti kako je ovaj uzorak dizajna veoma sličan uzorku dizajna Active Record u tome što su njihovi

objekti sami zaslužni za vlastito kreiranje, ažuriranje, čitanje i brisanje. Fowler (2003:153) navodi kako se ta

dva uzorka razlikuju po sljedećem: Active Record sadrži dodatnu poslovnu logiku, a Row Data Gateway ne

sadrži. U tom slučaju, ako bi se trebalo dodati dodatna poslovna logika, tada bi se trebala kreirati nova

podatkovna klasa koja koristi Row Data Gateway objekt za dohvaćanje podataka.

5.3.4. Struktura rješenja

Kao i za uzorak dizajna Active Record ne postoji određeni, grafički, način prikaza apstraktne

strukture ovog uzorka dizajna. Sve što je potrebno je implementirati strukturu Row Data Gateway objekta da

odgovara strukturi zapisa u bazi podataka.

Slika 5.3.1. prikazuje dijagram klasa za klasu Entity s metodama potrebnim za provođenjem operacija nad

bazom podataka i čija objektna struktura odgovara strukturi relacijske tablice entity čiji ER model je prikazan

na istoj slici. Objekt smije sadržavati metode za dohvaćanje i postavljanje vrijednosti polja, ali ne smije

sadržavati dodatnu poslovnu logiku. Ako sadrži poslovnu logiku, onda se implementirao uzorak dizajna

Active Record.

Page 40: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

36

Slika 5.3.1. Row Data Gateway klasa Entity povezana s relacijskom tablicom "entity"

5.3.5. Primjer

Uzorak dizajna Row Data Gateway se može implementirati na isti način kao i Active Record. Jedina

iznimka je što ovaj uzorak ne sadrži dodatnu poslovnu logiku, a Active Record smije. Prema tome, ovaj

primjer se neće objašnjavati korak po korak već će se odmah prikazati cjelokupan programski kod klasa.

Nastavlja se s prethodnim dogovorom gdje klase entiteta nasljeđuju apstraktnu klasu Entity koja je prikazana

na u primjeru koda 5.3.1.

Primjer koda 5.3.1. Apstraktna klasa Entity

public abstract class Entity { protected long id; public long getId() { return id; } public void setId(long id) { this.id = id; } }

Zatim, za ovaj primjer, kreirati će se apstraktna i generička klasa RowDataGateway koja će implementirati

temeljnu logiku za preslikavanje podataka između objekta i baze podataka. Ta klasa je prikazana u primjeru

koda 5.3.2.

Primjer koda 5.3.2. Apstraktna i generička klasa RowDataGateway

public abstract class RowDataGateway<T> extends Entity { public void create() {

Page 41: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

37

try (Connection conn = createConnection(); PreparedStatement ps = conn.prepareStatement( getCreateStatement(), Statement.RETURN_GENERATED_KEYS)) { setCreateStatementParameters(ps); ps.execute(); try (ResultSet rs = ps.getGeneratedKeys()) { if (rs.next()) { setId(rs.getLong(1)); } } } catch (SQLException ex) { System.out.println("Unable to create entity."); ex.printStackTrace(System.out); } } public void update() { try (Connection conn = createConnection(); PreparedStatement ps = conn.prepareStatement(getUpdateStatement())) { setUpdateStatementParameters(ps); ps.execute(); } catch (SQLException ex) { System.out.println("Unable to update entity."); ex.printStackTrace(System.out); } } public void delete() { try (Connection conn = createConnection(); PreparedStatement ps = conn.prepareStatement(getDeleteStatement())) { setDeleteStatementParameters(ps); ps.execute(); } catch (SQLException ex) { System.out.println("Unable to delete entity."); ex.printStackTrace(System.out); } } public void loadById(long id) { try (Connection conn = createConnection(); PreparedStatement ps = conn.prepareStatement( getSelectByIdStatement())) { setSelectByIdStatementParameters(ps, id); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { loadFromResultSet(rs); } } } catch (SQLException ex) { System.out.println("Unable to load entity by ID."); ex.printStackTrace(System.out); } } public void loadFromResultSet(ResultSet rs) { try { doLoadFromResultSet(rs); } catch (SQLException ex) { System.out.println("Unable to load entity from result set."); ex.printStackTrace(System.out); } } protected Connection createConnection() {

Page 42: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

38

try { Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance(); return DriverManager.getConnection( "jdbc:derby://localhost:1527/mydb", "username", "password"); } catch (Exception ex) { throw new RuntimeException("Unable to connect to the database."); } } protected abstract String getUpdateStatement(); protected abstract String getCreateStatement(); protected abstract String getDeleteStatement(); protected abstract String getSelectByIdStatement(); protected abstract void setCreateStatementParameters(PreparedStatement ps) throws SQLException; protected abstract void setUpdateStatementParameters(PreparedStatement ps) throws SQLException; protected abstract void setDeleteStatementParameters(PreparedStatement ps) throws SQLException; protected abstract void setSelectByIdStatementParameters( PreparedStatement ps, long id) throws SQLException; protected abstract void doLoadFromResultSet(ResultSet rs) throws SQLException; }

Nakon toga, potrebno je kreirati konkretnu implementaciju apstraktne klase RowDataGateway.

Primjer koda 5.3.3. pokazuje njenu konkretnu implementaciju, nazvanu LicenseGateway, za entitet licence

koji sadrži polje za ID (definirano u klasi Entity), naziv licence i njen opis. Na tu klasu dodana je ključna

riječ final kako bi se onemogućila njena daljnja proširenja putem podklasa.

Primjer koda 5.3.3.Implementacija apstraktne klase RowDataGateway u klasi LicenseGateway

public final class LicenseGateway extends RowDataGateway<License> { private static final String CREATE_STATEMENT = "INSERT INTO license VALUES (DEFAULT, ?, ?)"; private static final String UPDATE_STATEMENT = "UPDATE license SET name=?, description=? WHERE id=?"; private static final String DELETE_STATEMENT = "DELETE FROM license WHERE id=?"; private static final String SELECT_BY_ID_STATEMENT = "SELECT * FROM license WHERE id=?"; private String name; private String description; public String getName() { return name; } public String getDescription() { return description; } public void setName(String name) { this.name = name; } public void setDescription(String description) {

Page 43: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

39

this.description = description; } @Override protected String getCreateStatement() { return CREATE_STATEMENT; } @Override protected String getUpdateStatement() { return UPDATE_STATEMENT; } @Override protected String getDeleteStatement() { return DELETE_STATEMENT; } @Override protected String getSelectByIdStatement() { return SELECT_BY_ID_STATEMENT; } @Override protected void setCreateStatementParameters(PreparedStatement ps) throws SQLException { ps.setString(1, getName()); ps.setString(2, getDescription()); } @Override protected void setUpdateStatementParameters(PreparedStatement ps) throws SQLException { ps.setString(1, getName()); ps.setString(2, getDescription()); ps.setLong(3, getId()); } @Override protected void setDeleteStatementParameters(PreparedStatement ps) throws SQLException { ps.setLong(1, getId()); } @Override protected void setSelectByIdStatementParameters(PreparedStatement ps, long id) throws SQLException { ps.setLong(1, id); } @Override protected void doLoadFromResultSet(ResultSet rs) throws SQLException { setId(rs.getLong("id")); setName(rs.getString("name")); setDescription(rs.getString("description")); } }

Nadalje, može se koristiti direktno klasa LicenseGateway za podatake, ali ako se želi odvojiti

podatkovni objekt od objekta za preslikavanje ili se želi dodati poslovna logika za objekt, tada treba kreirati

novu klasa za podatak. Ta klasa će moći koristiti LicenseGateway u konstruktoru kako bi prenijela podatke

iz njega. Primjer koda 5.3.4. prikazuje klasu License koja ima dva konstruktora: jedan prazan, a drugi prima

Page 44: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

40

parametar tipa LicenseGateway.

Primjer koda 5.3.4. Klasa License

public class License extends Entity { private String name; private String description; public License() { } public License(LicenseGateway licenseGateway) { this.id = licenseGateway.getId(); this.name = licenseGateway.getName(); this.description = licenseGateway.getDescription(); } public String getName() { return name; } public String getDescription() { return description; } public void setName(String name) { this.name = name; } public void setDescription(String description) { this.description = description; } // Dodatna poslovna logika. }

U tom slučaju, za klasu LicenseGateway će se također morati dodati konstruktori koji će učitavati podatka iz

objekta License kako bi se omogućilo preslikavanje podataka ako su izmjene napravljene upravo u takvom

objektu. Primjer koda 5.3.5. pokazuje ta dva konstruktora za klasu LicenseGateway.

Primjer koda 5.3.5. Konstruktori za klasu LicenseGateway

public class LicenseGateway extends RowDataGateway<License> { // ... public LicenseGateway() { } public LicenseGateway(License license) { this.id = license.getId(); this.name = license.getName(); this.description = license.getDescription(); } // ... }

Page 45: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

41

5.4. Query Object

5.4.1. Namjera

Objekt koji predstavlja upit nad bazom podataka (Fowler, 2003:316).

5.4.2. Problem

Pisanje SQL upita u nekom programskom jeziku se uglavnom svodi na pisanjem upita kao String

objekta ili (u slučaju programskog jezika Java) u StringBuffer ili StringBuilder objekte ako se treba dinamički

složiti upit. Ovdje može doći do sljedećih problema:

• programer ne poznaje sintaksu SQL upita (Fowler, 2003:316),

• mogućnost pojave sintaktičkih greški, pogotovo ako se radi o velikim, složenim, upitima ili ako se

radi neki slaže upit putem uvjetovanih naredbi.

5.4.3. Rješenje

Query Object je specijalizirani uzorak dizajna Interpreter koji predstavlja strukturu objekata pomoću

kojih se gradi SQL upit (Fowler, 2003:316). Ovaj uzorak dizajna može biti relativno jednostavan ili relativno

složen, ovisno o tome kako je implementiran. Isto tako se može implementirati na različite načine:

• Jedna mogućnost je implementirati mehanizam koji jednostavno vraća valjan SQL upit na temelju

pridruženih objekata i vrijednosti.

• Druga mogućnost je mehanizam koji, umjesto generiranja SQL upita, služi za dohvat i filtriranje

objekata učitanih u memoriju (Fowler, 2003:317).

• Treća mogućnost je mehanizam koji može generirati SQL upit na temelju proslijeđenog objekta

(Fowler, 2003:317). Na primjer, ako se uzme objekt koji predstavlja osobu, tom objektu se postavi

vrijednost imena na Ivan i sva ostala polja ostaju prazna, mehanizam će generirati SQL upit koji

služi za pretraživanje svih osoba u bazi podataka koja se zovu Ivan (Fowler, 2003:317). Ovakav

mehanizam postoji u nekim NoSQL3 bazama podataka, npr. MongoDB.

• itd.

3NoSQL baze podataka su baze podataka koje ne koriste relacijske tablice već koriste vlastite načine pohrane

podataka. Primjer takvih baza podataka su CouchDB i MongoDB, koje koriste JSON za pohranu.

Page 46: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

42

5.4.4. Struktura rješenja

Slika 5.4.1. Primjer strukture rješenja za uzorak dizajna Query Object

Slika 5.4.1. prikazuje jednostavan primjer strukture rješenja za uzorak dizajna Query Object, a

elementi te strukture imaju sljedeće uloge:

• Criteria je sučelje za objekte koji predstavljaju ograničenja koja se nalaze unutar WHERE klauzule

u SELECT upitu.

• Condition predstavlja jednostavna ograničenja poput jednakosti, veće od, manje od, itd.

• Junction predstavlja složenija ograničenja koja se sastoje od više jednostavnih ograničenja koji se

nalaze u konjunkciji ili disjunkciji.

• Query je objekt koji sadrži podatke o tablici nad kojom se želi provesti upit i sadrži strukturu

ograničenja za WHERE klauzulu. Također može sadržavati i ostale klauzule SELECT upita, poput

ORDER BY, GROUP BY, LIMIT, itd.

5.4.5. Primjer

U ovom primjeru napraviti će se nešto drugačije: klase čiji objekti predstavljaju specifične podatke

iz baze podataka (npr. prethodno korišteni Employee, Skill, itd.) nasljeđivati će apstraktnu klasu. Navedena

apstraktna klasa, prikazana u primjeru koda 5.4.1., sadržati će metode za dohvaćanje i postavljanje ID

podatka (pod pretpostavkom da sve tablice u bazi podataka sadrže stupac id kao primarni ključ), apstraktnu

metodu koja vraća atribute (stupce) i apstraktni metodu koja vraća naziv entiteta (tablice).

Primjer koda 5.4.1. Apstraktna klasa Entity

public abstract class Entity {

protected long id;

public long getID() { return id; }

public void setID(long id) { this.id = id; }

public abstract String entityName();

public abstract String[] attributes();

}

Apstraktna klasa Entity omogućit će određenu vrstu fleksibilnosti kod implementacije uzorka dizajna Query

Object jer će se pomoću metoda entityName() i attributes() moći ispitati naziv tablice na koju se objekt

odnosi i strukturu tablice (tj. nazive stupaca od kojih se sastoji tablica). Budući da su te dvije metode

Page 47: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

43

apstraktne, za svaku klasu koja nasljeđuje Entity morati će se odrediti koje vrijednosti one vraćaju.

Primjer koda 5.4.2. prikazuje klasu Employee koja nasljeđuje Entity i implementira spomenute apstraktne

metode.

Primjer koda 5.4.2. Klasa Employee koja nasljeđuje Entity

public class Employee extends Entity {

private String firstName;

private String lastName;

// Getter i setter metode

@Override

public String entityName() {

return "employee";

}

@Override

public String[] attributes() {

return new String[] { "id", "first_name", "last_name" };

}

}

Sada, implementirati će se klase koja će predstavljati ograničenja, odnosno uvjete, u WHERE klauzulama

SQL upita. Spomenute klase implementirati će se na temelju uzorka dizajna Interpreter opisan u knjizi od

Gamma et al (1995). Prvo će se definirati sučelje za ograničenja kao u primjeru koda 5.4.3. Fowler (2003:318-

320) je u svojim primjerima koristio Criteria za naziv tih objekata u kodu, pa će se isto koristiti za naziv

sučelja (ovdje prestaju sličnosti s Fowlerovim primjerima).

Primjer koda 5.4.3. Sučelje Criteria

public interface Criteria {

String toSqlString();

}

Sučelje u primjeru koda 5.4.3. definira samo jednu metodu koja će vraćati ograničenja kao String objekt, ali

u formatu u kojem bi se objekt mogao koristiti u sklopu WHERE klauzule. Sljedeće, implementirati će se

klasa Condition koja nasljeđuje sučelje Criteria i predstavlja jednostavno ograničenje u WHERE klauzuli

koje se sastoji od: imena stupca (atributa), operatora i vrijednosti. Implementacija klase Condition prikazana

je u primjeru koda 5.4.4.

Primjer koda 5.4.4. Klasa Condition

public class Condition implements Criteria {

private String attribute;

private String operator;

private Object value;

Page 48: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

44

public Condition(String attribute, String operator, Object value) {

this.attribute = attribute;

this.operator = operator;

this.value = value;

}

@Override

public String toSqlString() {

return attribute

+ " " + operator

+ " " + (value instanceof Number ? value : "'" + value + "'");

}

}

Nakon toga, implementirati će se klasa Junction. Navedena klasa predstavljati će niz ograničenja koji su

međusobno povezani operatorom, npr. operatorom disjunkcije (OR) ili operatorom konjunkcije (AND).

Implementacija klase Junction prikazana je u primjeru koda 5.4.5.

Primjer koda 5.4.5. Klasa Junction

public class Junction implements Criteria {

private String operator;

private List<Criteria> criterias = new ArrayList<>();

public Junction(String operator, Criteria... criterias) {

Collections.addAll(this.criterias, criterias);

this.operator = operator;

}

public void add(Criteria criteria) {

criterias.add(criteria);

}

public boolean isEmpty() {

return criterias.isEmpty();

}

@Override

public String toSqlString() {

StringJoiner sj = new StringJoiner(" " + operator + " ");

for (Criteria c : criterias) {

if (c instanceof Junction) {

sj.add("(" + c.toSqlString() + ")");

} else {

sj.add(c.toSqlString());

}

}

return sj.toString();

}

}

Kako bi se olakšalo programeru kreiranje pravilnih objekata ograničenja, može se u klasama Condition i

Junction definirati statičke metode koje bi vraćale predefinirana ograničenja. Primjer koda 5.4.6. prikazuje

Page 49: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

45

definiciju nekih od statičkih metoda u klasi Condition, a primjer koda 5.4.7. definiciju statičkih metoda u

klasi Junction.

Primjer koda 5.4.6. Statičke metode koje vraćaju predefinirane objekte Condition

public class Condition implements Criteria {

// ...

public static Condition eq(String attribute, Object value) {

return new Condition(attribute, "=", value);

}

public static Condition notEq(String attribute, Object value) {

return new Condition(attribute, "<>", value);

}

public static Condition gt(String attribute, Object value) {

return new Condition(attribute, ">", value);

}

public static Condition lt(String attribute, Object value) {

return new Condition(attribute, "<", value);

}

public static Condition geq(String attribute, Object value) {

return new Condition(attribute, ">=", value);

}

public static Condition leq(String attribute, Object value) {

return new Condition(attribute, "<=", value);

}

public static Condition like(String attribute, String value) {

return new Condition(attribute, "LIKE", value);

}

}

Primjer koda 5.4.7. Statičke metode koje vraćaju predefinirane objekte Junction

public class Junction implements Criteria {

// ...

public static Junction and(Criteria... criterias) {

return new Junction("AND", criterias);

}

public static Junction or(Criteria... criterias) {

return new Junction("OR", criterias);

}

}

Sve što je ostalo je implementirati klasu Query koja će na temelju danih objekata tipa Entity i ograničenja

generirati SQL upit. Klasa Query sadržat će dva polja, također prikazana u primjeru koda 5.4.8., a oni će biti:

Page 50: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

46

• polje entities, mapa objekata tipa Entity s ključem tipa String koji će predstavljati pseudonim (eng.

alias) za tablicu u bazi podataka,

• polje criterias, objekt tipa Junction, odnosno niz ograničenja koji će, u ovom slučaju, biti povezani

logičkim operatorom konjunkcije (AND).

Primjer koda 5.4.8. Polja klase Query

public class Query {

private Map<String, Entity> entities = new HashMap<>();

private Junction criterias = Junction.and();

// ...

}

Sljedeće, potrebne su metode za dodavanje objekata tipa Entity u polje entities, koje se mogu vidjeti u

primjer koda 5.4.9. U istom primjeru također su prikazani konstruktori klase Query koji koriste metode za

dodavanje. Uvođenjem konstruktora za ovu klasu koji zahtijevaju dodavanje objekta tipa Entity sprečava se

kreiranje objekta Query s praznom mapom, što bi dovelo do komplikacija oko generiranja SQL upita.

Jedna metoda za dodavanje kao parametar prima samo objekti tipa Entity kojeg dodaje u mapu, ali za ključ,

odnosno njegov pseudonim, koristi naziv entiteta. Druga metoda prima dva parametra: objekt tipa Entity i

pseudonim za taj entitet. Za ključ se tada koristi proslijeđeni pseudonim.

Primjer koda 5.4.9. Konstruktori klase Query i metode za dodavanje objekata tipa Entity

public class Query {

// ...

public Query(Entity entity) {

addEntity(entity);

}

public Query(Entity entity, String alias) {

addEntity(entity, alias);

}

public void addEntity(Entity entity) {

entities.put(entity.entityName(), entity);

}

public void addEntity(Entity entity, String alias) {

entities.put(alias, entity);

}

// ...

}

Također je potrebna metoda za dodavanje ograničenja za WHERE klauzulu. Za klasu Junction, u primjeru

koda 5.4.5., definirana je operacija dodavanja ograničenja u objekt te klase. Metoda za dodavanje ograničenja

Page 51: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

47

u objektu Query će ustvari koristiti metodu dodavanja ograničenja od polja criterias. Primjer koda 5.4.10.

prikazuje tu metodu za dodavanje ograničenja.

Primjer koda 5.4.10. Metoda za dodavanja ograničenja u objekt Query

public class Query {

// ...

public void addCriteria(Criteria criteria) {

criterias.add(criteria);

}

// ...

}

Ostalo je definirati metodu koja bi vratila SQL upit kao objekt tipa String. Za to će se nadjačati metoda

toString() koja će na temelju trenutnog stanja objekta Query, odnosno na temelju stanja polja entities i

criterias od kojih se sastoji spomenuti objekt, generirati SQL upit. U primjeru koda 5.4.11. metoda

toString() koristi dodatne privatne metode od koje svaki generira zasebni klauzule SQL upita (jedan generira

SELECT klauzula, drugi generira FROM klauzula, a treći generira WHERE klauzulu).

Primjer koda 5.4.11. Nadjačavanje toString() metoda koja vraća SQL upit

public class Query {

// ...

@Override

public String toString() {

String select = makeSelect();

String from = makeFrom();

String where = makeWhere();

return select + from + where;

}

private String makeSelect() {

StringJoiner sj = new StringJoiner(", ");

for (String alias : entities.keySet()) {

Entity entity = entities.get(alias);

for (String attr : entity.attributes()) {

sj.add(alias + "." + attr);

}

}

return "SELECT " + sj.toString();

}

private String makeFrom() {

StringJoiner sj = new StringJoiner(", ");

for (String alias : entities.keySet()) {

sj.add(entities.get(alias).entityName() + " " + alias);

}

return " FROM " + sj.toString();

}

Page 52: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

48

private String makeWhere() {

return criterias.isEmpty() ? "" : " WHERE " + criterias.toSqlString();

}

}

Primjer koda 5.4.12. prikazuje primjer korištenja klase Query.

Primjer koda 5.4.12. Primjer korištenja klase Query

Query query = new Query(new Employee(), "e");

Criteria c1 = Condition.eq("e.last_name", "Horvat")

Criteria c2 = Junction.or(

Condition.eq("e.first_name", "Ivan"),

Condition.eq("e.first_name", "Ivana"));

query.addCriteria(c1);

query.addCriteria(c2);

System.out.println(query.toString()); // SELECT e.id, e.first_name, e.last_name

// FROM employee e

// WHERE e.last_name = 'Horvat'

// AND (e.first_name = 'Ivan' OR

// e.first_name = 'Ivana')

Page 53: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

49

5.5. Table Data Gateway

5.5.1. Namjera

Objekt koji učahuruje komunikaciju sa specifičnom relacijskom tablicom u bazi podataka (Fowler,

2003:144).

5.5.2. Problem

Glavni problem kojeg Fowler (2003:114) opisuje, a kojega rješava ovaj uzorak dizajna, je što neki

programeri nisu upoznati sa SQL sintaksom, a oni koji jesu ponekad ne napišu dobre upite.

5.5.3. Rješenje

Rješenje ovog problema je učahuriti svu komunikaciju s relacijskom tablicom u jedan objekt. Jedan

takav objekt se podudara s jednom relacijskom tablicom, što znači da ako se ovaj uzorak dizajna želi koristiti

za sve tablice u bazi podataka (ne računajući tablice koje se koriste za ostvarenje veze više-više između

tablica), onda će postojati i toliko objekata.

Objekt Table Data Gateway bi imao nekoliko metoda za dohvat podataka iz relacijske tablice (na programeru

je da odredi metode koje su potrebne ili doda nove metode po potrebi) i metoda za unošenje podataka u

tablicu (INSERT), ažuriranje (UPDATE) i brisanje (DELETE) podataka (Fowler, 2003:144).

Treba napomenuti da ovaj uzorak dizajna služi samo kao zamjena za konstantnim pisanjem istih SQL upita.

5.5.4. Struktura rješenja

Slika 5.5.1. Odnos između tablice "entity" i Row Data Gateway klase EntityGateway

Struktura ovog uzorka dizajna je jednostavna jer samo dva elementa sudjeluju u vezi: objekt koji komunicira

s bazom podataka, odnosno pristupa specifičnoj relacijskoj tablici, i sama baza podataka. Naravno, tu još

postoje podatkovni objekti koji predstavljaju jedan zapis iz baze podataka. Primjer na slici 5.5.1. prikazuje

odnos između klase EntityGateway relacijske tablice entity u tome kako bi otprilike izgledala implementacija

uzorka dizajna Table Row Gateway.

5.5.5. Primjer

Neka postoji relacijska tablica customer koja je kreirana na temelju SQL upita u primjeru koda 5.5.1.

(SQL kod koristi sintaksu za postavljanje inkrementalnog primarnog ključa kojeg koristi Apache Derby).

Primjer koda 5.5.1. SQL upit za kreiranje tablice "customer"

CREATE TABLE customer (

Page 54: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

50

id INT GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),

name VARCHAR(64),

address VARCHAR(64),

email VARCHAR(64),

phone VARCHAR(16),

PRIMARY KEY (id)

)

Također, neka postoji klasa entiteta Customer čija struktura i metode su prikazani u primjeru koda 5.5.2.

Primjer koda 5.5.2. Klasa Customer

public class Customer {

private long id;

private String name;

private String address;

private String email;

private String phoneNumber;

// Getter i setter metode.

}

Nadalje, kreirat će se metoda CustomerGateway koja će implementirati uzorak dizajna Table Data Gateway.

Za razliku od uzoraka Active Record, Data Mapper i Row Data Gateway, u ovom primjeru se neće napraviti

apstraktna generička klasa jer ovaj uzorak dizajna strogo ovisi o strukturi tablice u bazi podataka.

Prvo, definirati će se metoda za kreiranje novog zapisa u bazu podataka. Metoda će primati sve parametre

koji odgovaraju stupcima u bazi podataka osim stupca za ID, koji se sam generira. Primjer koda 5.5.3.

prikazuje metodu za kreiranje zapisa i također uključuje metodu za kreiranja veze prema bazi podataka koju

klasa koristi.

Primjer koda 5.5.3. Metoda za kreiranje zapisa + metoda za kreiranje veze prema bazi podataka

public class CustomerGateway {

protected Connection createConnection() {

try { Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance(); return DriverManager.getConnection( "jdbc:derby://localhost:1527/mydb", "username", "password"); } catch (Exception ex) { throw new RuntimeException("Unable to connect to the database."); }

}

public void create(String name,

String address,

String email,

String phoneNumber)

{

Page 55: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

51

String sql = "INSERT INTO customer VALUES (DEFAULT, ?, ?, ?, ?)";

try (Connection conn = createConnection();

PreparedStatement ps = conn.prepareStatement(sql)) {

ps.setString(1, name);

ps.setString(2, address);

ps.setString(3, email);

ps.setString(4, phoneNumber);

ps.execute();

} catch (SQLException ex) {

System.out.println("Unable to create Customer entity.");

ex.printStrackTrace(System.out);

}

}

// ...

}

Zatim, slijedi metoda za ažuriranje zapisa koja će za parametre primati sva polja koja čine entitet u bazi

podataka, uključujući ID koji je potreban za ažuriranje. Primjer koda 5.5.4. pokazuje tu metodu.

Primjer koda 5.5.4. Metoda za ažuriranje zapisa

public class CustomerGateway {

// ....

public void create(long id,

String name,

String address,

String email,

String phoneNumber)

{

String sql = "UPDATE customer SET name=?, address=?, email=?, phone=? "

+ "WHERE id=?";

try (Connection conn = createConnection();

PreparedStatement ps = conn.prepareStatement(sql)) {

ps.setString(1, name);

ps.setString(2, address);

ps.setString(3, email);

ps.setString(4, phoneNumber);

ps.setLong(5, id);

ps.execute();

} catch (SQLException ex) {

System.out.println("Unable to update Customer entity.");

ex.printStrackTrace(System.out);

}

}

// ...

}

Sljedeće, napraviti će se metoda za brisanje zapisa iz baze podataka. Za ovu metodu dovoljno je proslijediti

ID kao parametar. Metoda za brisanja prikazana je u primjeru koda 5.5.5.

Primjer koda 5.5.5. Metoda za brisanje zapisa

public class CustomerGateway {

// ....

public void create(long id) {

Page 56: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

52

String sql = "DELETE FROM customer WHERE id=?";

try (Connection conn = createConnection();

PreparedStatement ps = conn.prepareStatement(sql)) {

ps.setLong(5, id);

ps.execute();

} catch (SQLException ex) {

System.out.println("Unable to update Customer entity.");

ex.printStrackTrace(System.out);

}

}

// ...

}

Na kraju, ostalo je još implementirati metode za čitanje podataka. Programer ima slobodu dodavanja metoda

za čitanje koliko je potrebno. Primjer koda 5.5.6. definira dvije metode za čitanje podataka: prema njihovom

ID-u i prema njihovom nazivu. No, lagano se može dodati i čitanje prema ostalim poljima relacijske tablice.

Primjer koda 5.5.6. Metoda za čitanje podataka prema ID-u i nazivu

public class CustomerGateway {

// ....

private createCustomer(ResultSet rs) {

Customer customer = new Customer();

customer.setId(rs.getLong("id"));

customer.setName(rs.getString("name"));

customer.setAddress(rs.getString("address"));

customer.setEmail(rs.getString("email"));

customer.setPhoneNumber(rs.getString("phone"));

return customer;

}

public Customer findByID(long id) {

String sql = "SELECT * FROM customer WHERE id=?";

try (Connection conn = createConnection();

PreparedStatement ps = conn.prepareStatement(sql)) {

ps.setLong(1, id);

try (ResultSet rs = ps.executeQuery()) {

if (rs.next()) {

return createCustomer(rs);

} else {

return null;

}

}

} catch (SQLException ex) {

System.out.println("Unable to update Customer entity.");

ex.printStrackTrace(System.out);

return null;

}

}

public List<Customer> findByName(String name) {

String sql = "SELECT * FROM customer WHERE name=?";

List<Customer> customers = new ArrayList<>();

try (Connection conn = createConnection();

Page 57: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

53

PreparedStatement ps = conn.prepareStatement(sql)) {

ps.setLong(1, "%" + name + "%");

ps.execute();

try (ResultSet rs = ps.executeQuery()) {

while (rs.next()) {

customers.add(createCustomer);

}

}

} catch (SQLException ex) {

System.out.println("Unable to update Customer entity.");

ex.printStrackTrace(System.out);

}

return customers;

}

// ...

}

Page 58: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

54

5.6. Unit of Work

5.6.1. Namjera

Održava popis objekata nad koje je utjecala poslovna transakcija i koordinira upisivanje njihovih

izmjena i rješavanje konkurentnih problema kod višedretvenog rada (Fowler, 2003:184).

5.6.2. Problem

Fowler (2003:189) kao problem vezan za ovaj uzorak je praćenje izmjena podataka unutar neke

poslovne interakcije u aplikaciji koji se moraju sinkronizirati s podacima u bazi podataka.

Drugi problem kojeg Fowler spominje je broj poziva prema bazi podataka. Ako bi se nakon svake operacija

kreiranja, čitanja, ažuriranje ili brisanja promjene sinkronizirale s bazom podataka, baza podataka bi primila

veliki broj poziva prema njoj.

5.6.3. Rješenje

Rješenje opisanog problema je kreirati mehanizam koji bi pratio promjene u objektima i zahtjeve za

kreiranje novih objekata ili brisanje postojećih. Taj mehanizam bi, nakon što je poslovna transakcija od strane

aplikacije završila, otvorila transakciju s bazom podataka i provela zabilježene promjene u bazi podataka.

Fowler (2003:185-186) navodi dva načina kako da taj mehanizam zabilježi promjene koje se provode nad

objektom:

1. pozivatelj bilježi napravljene izmjene,

2. objekt bilježi napravljene izmjene nad njime.

U prvom slučaju, korisnik objekta mora se sjetiti zabilježiti objekt s Unit of Work mehanizmom kako bi se

provele izmjene (Fowler, 2003:185). Ako promjene nisu zabilježene unutar Unit of Work, onda te promjene

neće biti provedene u bazi podataka.

U drugom slučaju, objekt sam bilježi kod Unit of Work mehanizma izmjene provedene nad njime. Ako se

izmijenila vrijednost nekog polja u objektu, taj objekt bilježi tu izmjenu kod Unit of Work mehanizma. Ako

se objekt u aplikaciji označio za brisanje, objekt će zabilježiti kod zahtjev za brisanjem kod Unit of Work

mehanizma. I tako dalje. Naravno, ovakav način može jedino funkcionirati ako se Unit of Work objekt

proslijedi objektu ili Unit of Work objekt mora sadržavati globalni pristup do njega (Fowler, 2003:186).

5.6.4. Struktura rješenja

Ne postoji neka apstraktna struktura rješenja koja bi grafički prikazala arhitekturu uzorka dizajna

Unit of Work. Ono što je važno kod ovog uzorka dizajna je mogućnost bilježenja promjena nad objektima,

bilježenje kreiranje novih i brisanje postojećih objekata, te provođenja svih zabilježenih promjena unutar

transakcije u bazi podataka. Način implementacije ovog uzorka dizajna ovisi o programeru.

5.6.5. Primjer

Fowler (2003:190) je u svom primjeru za Unit of Work koristio nekoliko objekata liste, svaka bilježi

objekte za specifičan zahtjev (jedna lista je za novokreirane objekte, druga lista je za objekte koje treba

Page 59: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

55

ažurirati, itd.). U ovom primjeru, svi objekti će se bilježiti unutar jedne liste, ali će svaki objekt biti označen

za specifičan zahtjev.

Unutar klase UnitOfWork, definirati će se interno pobrojenje (eng. enumeration) kojim će se bilježiti vrsta

zahtjeva za objekt i definirati će se interna klasa koja će omotati objekt entiteta i pobrojenje u jedan objekt

čime bi se bilježila vrsta zahtjeva prema tom objektu. Spomenuto interno pobrojenje i interna klasa prikazani

su u primjeru koda 5.6.1.

Primjer koda 5.6.1. Interno probrojenje OperationMarker i interna klasa EntityMarkerWrapper

public class UnitOfWork {

private enum OperationMarker {

CREATION,

UPDATE,

REMOVAL

}

private class EntityMarkerWrapper<T extends Entity> {

final T entity;

final OperationMarker operationMarker;

public EntityMarkerWrapper(T entity, OperationMarker operationMarker) {

this.entity = entity;

this.operationMarker = operationMarker;

}

}

// ...

}

Ovaj primjer uzorka UnitOfWork koristiti će Data Mapper objekte koji bi proveli tražene operacije nad

objektima. No, za ovaj primjer neka su Data Mapper klase modificirane tako da se dodaju alternativne

metode create(), update() i delete() koje primaju objekt veze kao parametar. Te metode su dodane u

apstraktnoj klasu DataMapper koja je opisana u primjeru tog uzorka u poglavlju 5.2.5. Primjer koda 5.6.2.

pokazuje te metode.

Primjer koda 5.6.2. Metode za kreiranje, ažuriranje i brisanje zapisa

koje prihvaćaju objekt veze kao parametar

public abstract class DataMapper<T extends Entity> {

// ...

public void create(Connection conn, T entity) throws SQLException {

try (PreparedStatement ps = conn.prepareStatement(

createStatement(),

Statement.RETURN_GENERATED_KEYS)) {

setCreateStatementParameters(ps, entity);

ps.execute();

try (ResultSet rs = ps.getGeneratedKeys()) {

Page 60: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

56

rs.next();

entity.setId(rs.getLong(1));

}

}

}

public void update(Connection conn, T entity) throws SQLException {

try (PreparedStatement ps = conn.prepareStatement(updateStatement())) {

setUpdateStatementParameters(ps, entity);

ps.execute();

}

}

public void delete(Connection conn, T entity) throws SQLException {

try (PreparedStatement ps = conn.prepareStatement(deleteStatement())) {

setDeleteStatementParameters(ps, entity);

ps.execute();

}

}

// ...

}

Klasa UnitOfWork će sadržavati listu objekata, omotani u objektu EntityMarkerWrapper, nad kojima se

provodi zahtjevi za kreiranjem, ažuriranjem ili brisanje, i sadržati će mapu Data Mapper objekata koji će

provoditi tražena preslikavanja. U konstruktoru će se dodavati objekti preslikavanja. Mapa će koristiti klasu

entiteta kao ključ kojim bi se pretraživali objekti za preslikavanje Primjer koda 5.6.3. prikazuje listu objekata,

mapu objekata preslikavanja i konstruktor.

Primjer koda 5.6.3. Lista objekata, mapa objekata preslikavanje i konstruktor klase UnitOfWork

public class UnitOfWork {

// ...

private final Map<

Class<? extends Entity>,

DataMapper<? extends Entity>> mappers;

private final List<EntityMarkerWrapper<? extends Entity>> markedEntities;

public UnitOfWork() {

this.mappers = new HashMap<>();

// Dodavanje objekata preslikavanje u mapu mappers

this.markedEntities = new ArrayList<>();

}

// ...

}

Sljedeće, definirati će se metode kojima bi se označavale vrste zahtjeva koja se želi provesti nad objekt. Te

metode će onda omotati objekte entiteta s odgovarajućim pobrojenjem iz definiranim u OperationMarker u

objekt EntityMarkerWrapper i dodati u listu označenih objekata. Primjer koda 5.6.4. prikazuje te metode.

Page 61: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

57

Primjer koda 5.6.4.Metode za bilježenje objekata entiteta za određenu operaciju

public class UnitOfWork {

// ...

public <T extends Entity> void markForCreation(T entity) {

markedEntities.add(

new EntityMarkerWrapper<>(entity, OperationMarker.CREATION));

}

public <T extends Entity> void markForUpdate(T entity) {

markedEntities.add(

new EntityMarkerWrapper<>(entity, OperationMarker.UPDATE));

}

public <T extends Entity> void markForRemoval(T entity) {

markedEntities.add(

new EntityMarkerWrapper<>(entity, OperationMarker.REMOVAL));

}

// ...

}

Ono što nedostaje u primjeru koda 5.6.4. je provjera je li se objekt već zabilježio za kreiranje ili brisanje. No,

samo za primjer i ovo je dovoljno.

Ostaje još definirati metodu koja će provesti označene operacije nad objektima. Ta metoda izvršava operacije

po FIFO (First In First Out) principu – u svakoj iteraciji izvlači jedan objekt iz liste i provodi zabilježenu

operaciju pomoću odgovarajućeg Data Mapper objekta. Sve operacije će se provesti u jednoj transakciji. U

ovom slučaju objekt UnitOfWork se brine o kreiranju vlastite veze prema bazi podataka. Primjer metode za

provođenje zabilježenih operacija nad objektima (i metoda za kreiranje veze prema bazi podataka) dane su u

primjeru koda 5.6.5.

Primjer koda 5.6.5.Metode za provođenje zabilježenih operacija nad objektima

(i metoda za kreiranje veze prema bazi podataka)

public class UnitOfWork {

// ...

public void save() {

Connection conn = null;

try {

conn = createConnection();

conn.setAutoCommit(false);

while (!markedEntities.isEmpty()) {

EntityMarkerWrapper emw = markedEntities.remove(0);

DataMapper dm = mappers.get(emw.entity.getClass());

switch (emw.operationMarker) {

case CREATION: dm.create(conn, emw.entity); break;

case UPDATE: dm.update(conn, emw.entity); break;

case REMOVAL: dm.delete(conn, emw.entity); break;

}

}

Page 62: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

58

conn.commit();

} catch (SQLException ex) {

System.out.println("Transaction error.");

ex.printStackTrace(System.out);

if (conn != null) {

try {

conn.rollback();

} catch (SQLException ex1) {

ex.printStackTrace(System.out);

}

}

} finally {

if (conn != null) {

try {

conn.close();

} catch (SQLException ex) {

ex.printStackTrace(System.out);

}

}

}

}

private Connection createConnection() {

try {

Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance();

return DriverManager.getConnection(

"jdbc:derby://localhost:1527/mydb",

"username",

"password");

} catch (Exception ex) {

ex.printStackTrace(System.out);

throw new RuntimeException(ex);

}

}

}

Primjer koda 5.6.6. prikazuje primjer kako bi se objekt klase UnitOfWork mogla primjenjivati u programskom

kodu neke aplikacije.

Primjer koda 5.6.6.Primjer korištenja objekta klase UnitOfWork

UnitOfWork uow = new UnitOfWork();

// ...

uow.markForCreation(entityToCreate1);

uow.markForCreation(entityToCreate2);

uow.markForRemoval(entityToRemove);

uow.markForUpdate(entityToUpdate);

uow.save();

Page 63: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

59

6. Uzorci dizajna za ORM sustave

Ovo poglavlje će biti drugačije od poglavlja 4. Uzorci dizajna za podatkovni sloj i poglavlja 5. Uzorci

dizajna za rad s bazom podataka u tome što se neće opisivati novi uzorci dizajna. Nego, uzeti će se određeni

uzorci dizajna opisani u prethodno spomenutim poglavljima i opisati zašto bi oni bili korisni u izgradnji ORM

sustava.

Kao pomoć za pisanje ovog poglavlja korištene je korisnička dokumentacija od tvrtke Oracle (2013) za Java

EE 6. Specifično, koristiti će se poglavlje o Java Persistence API (nadalje JPA). Navedeni API pruža

programerima funkcionalnost preslikavanja podataka između objekata i relacijskih tablica za Java aplikacije

(Oracle, 2013:579). Na temelju opisa pojedinih elemenata JPA odrediti će se koji od opisanih uzoraka, iz

četvrtog i petog poglavlja, bi bio primijenjiv za izgradnju vlastitog ORM sustava.

Spomenuta korisnička dokumentacija se koristi jer, uz to što je dobro napisana, dobro opisuje elemente API

koji bi se koristili u vlastitim ORM sustavima. Kao dodatak koristi se i korisnička dokumentacija za Hibernate

ORM (Mihalcea et al., 2017), poznati ORM radni okvir otvorenog koda. Navedeni radni okvir koristi

elemente JPA i sama dokumentacija napisana slično poglavlju u Oracle-ovoj korisničkoj dokumentaciji za

JPA.

Nadalje, uzorci koji će se navesti neće koristiti poseban predložak za njihov opis, kao što je korišteno u

četvrtom i petom poglavlju. Umjesto toga, jednostavno će se opisati kako bi identificrani uzorci dizajna bili

korisni za igradnju vlastitog ORM sustava. Naziv potpoglavlja sadržavati će naziv uzorka dizajna koji je

identificiran, ali ako je više uzoraka dizajna primjenjivo na isti ili sličan način tada će se ti uzorci dizajna

grupirati pod odgovarajućim nazivom za poglavlje (npr. uzorci dizajna Active Record, Data Mapper, Row

Data Gateway i Metadata Mapping će se grupirati pod nazivom "Uzorci dizajna za preslikavanje").

6.1. Uzorci dizajna za preslikavanje

Kako ORM sustavi služe za preslikavanje podataka između objekata u objektnom-orijentiranom

sustavu i tablica u relacijskoj bazi podataka, logično je zaključiti da bi se u ORM sustav mogao

implementirati jedan od uzoraka dizajna koji se bave preslikavanjem. Ti uzorci dizajna su: Active Record,

Data Mapper, Row Data Gateway i Metadata Mapping. Uzorak dizajna Table Data Gateway nije uključen

pod uzorke dizajna za preslikavanje jer ono ne vrši preslikavanje, nego služi samo kao zamjena za

konstantnim pisanjem sirovih SQL upita.

Fowler (2003:153) predlaže korištenje uzoraka dizajna Active Record ili Row Data Gateway ako radi o

jednostavnom preslikavanju, a za kompleksnija preslikavanja koristiti uzorak dizajna Data Mapper. No,

kompleksnost preslikavanja nije toliko važno koliko je važna fleksibilnost preslikavanja. ORM sustav bi

trebao znati, za bilo koji objekt entiteta, u koju relacijsku tablicu preslikavati podatke, koji stupac iz relacijske

tablice odgovara nekom polju iz objekta, itd. Bez načina kako da ORM sustav očita te informacije, teško će

se moći kreirati fleksibilan sustav za preslikavanje podataka.

No, zato na scenu stupa uzorak dizajna Metadata Mapping. Metadata Mapping koristi određenu vrstu

Page 64: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

60

metapodataka na temelju kojih bi aplikacija, odnosno sustav za preslikavanje, mogao dokučiti kako

preslikavati podatke. Metapodaci mogu biti implementirani pomoću: 1) refleksije i 2) posebne datoteke. JPA

opisuje korištenje refleksije, odnosno anotacija, kao metapodatka, dok Hibernate ORM programerima na

raspolaganju omogućuje korištenje metapodataka kao anotacija i kao datoteke.

Moglo bi se reći da je uzorak dizajna Metadata Mapping najbolji izbor za implementaciju funkcije

preslikavanja u vlastitom ORM sustavu. Ali, Metadata Mapping se može kombinirati i s drugim uzorcima

dizajna za preslikavanje kako bi se ostvarila funkcionalnost fleksibilnog preslikavanja. Kratkim

pretraživanjem na Google Web tražilici pronađen je ActiveJPA radni okvir - ORM radni okvir koji se temelji

na Active Record uzorku dizajna i koristi anotacije kao metapodatke.

6.2. Uzorci dizajna hijerarhije nasljeđivanja tablica

JPA (Oracle, 2003:592) podržava razne strategije za preslikavanje nasljeđivanja (eng. inheritance

mapping strategies) neke hijerarhije klasa. Radi se o mehanizmu koji preslikava podatke iz hijerarhije klasa

u odgovarajuću hijerarhiju tablica iz relacijske baze podataka. Svaka od tih strategija odgovara jednom od

uzoraka dizajna hijerarhije nasljeđivanja tablica, a to su: Single Table Inheritance, Class Table Inheritance i

Concrete Table Inheritance. Hibernate ORM (Mihalcea et al., 2017, 2.11. Inheritance) koristi isti mehanizam

preslikavanja podataka na temelju hijerarhije tablica.

Strategije za preslikavanje nasljeđivanja su (Oracle, 2003:593-594):

• Jedna tablica po hijerarhiji klasa (eng. Single Tablce per Class Hierarchy; odgovara uzorku dizajna

Single Table Inheritance),

• Jedna tablica po konkretnoj klasi (eng. Table per Concrete Class; odgovara uzorku dizajna Concrete

Table Inheritance),

• Spojene podklase (eng. Joined Subclass; odgovara uzorku dizajna Class Table Inheritance).

Kako ti mehanizmi postoje u spomenutim JPA i Hibernate ORM-u, navedeni uzorci dizajna hijerarhije

nasljeđivanja tablica mogli bi se razmotriti za korištenje u vlastitom ORM sustavu.

6.3. Uzorci dizajna za mnogostrukost veza između relacijskih

tablica

JPA (Oracle, 2003:587) navodi podršku za mnogostrukost veza između entiteta, odnosno asocijacije.

To su veze jedan-jedan, jedan-više, više-jedan i više-više. U JPA (Oracle, 2003:587) te veze se označavaju s

posebnim anotacijama nad odgovarajućem polju u klasi entiteta.

No, da bi te anotacije funkcionirale, tablice u bazi podataka moraju biti strukturirane na određen način.Ako

se neko polje u objektu entiteta označi s anotacijom s vrstom veze jedan-jedan, jedan-više i više-jedan, onda

treba postojati vanjski ključ u jednoj ili objem tablicama. Ako se neko polje u objektu entiteta označi s

anotacijom za vrstu veze više-više, onda treba postojati dodatna tablica koja spaja dvije tablice koje su u

takvoj vezi.

Page 65: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

61

Moglo bi se reći da je potrebno ORM sustavima dati do znanja jesu nad tablicama u relacijskoj bazi podataka

primijenjeni uzorci dizajna Foreign Key Mapping i Association Table Mapping.

6.4. Embedded Value

Oracle (2003:590) navodi podršku za ugrađene klase (eng. Embeddable Classes) za JPA. To su klase

čiji objekti odgovaraju dva ili više stupaca neke tablice. To odgovara uzorku dizajna Embedded Value.

Prednosti tog uzorka dizajna su jasne: omogućava grupiranje stupaca u jedan objekt koji predstavlja smislenu

cjelinu. Programer vlastitog ORM sustava može odlučiti želi li omogućiti preslikavanje podataka iz više

stupaca u jedan objekt unutar objekta entiteta.

6.5. Identity Field

Primarni ključevi su korišteni kao jedinstvene identifikacijske oznake redaka u nekoj relacijskoj

tablici. Logično je zaključiti da će ORM sustav često zahtijevati poznavanje primarni ključ podatka kako bi

izvršio operacije poput ažuriranja i brisanja, pa čak i čitanja podataka. Prema tome, Identity Field je uzorak

dizajna koji će se definitivno implementirati za ORM sustav, ali treba razmisliti kako ga treba implementirati.

Korisnička dokumentacija za Java EE 6 (Oracle, 2003:585-586) za JPA navodi neka pravila za vezana uz

primarne ključeve koji bi se mogli gledati i kao prijedlozi u implementaciji vlastitog ORM sustava. Na

primjer, jednostavni primitivni ključevi se označavaju s anotacijom @javax.persistence.Id, za složene

ključeve treba se kreirati posebna klasa i oni se označavaju s anotacijama @javax.persistence.EmbeddedId

i @javax.persistence.IdClass Oracle, 2003:585).

6.6. Identity Map

Korisnička dokumentacija za Hibernate ORM (Mihalcea et al., 2017, 2.5.7. Implementing equals()

and hashCode()) objašnjava kako Hibernate osigurava da višestruko učitavanje istog entiteta rezultira

vraćanjem iste instance tog entiteta. Time se rješava problem duplikata entiteta u kojima može doći do

problema sinkronizacije, odnosno ako je jedan objekt entiteta ažuriran, ostali nisu. To također rješava i

problem prevelikog broja objekata učitanih u memoriju.

Takav problem rješava i uzorak dizajna Identity Map. Svaki put kada se učita entitet iz baze podataka, koji

prethodno nije bio učitan, taj objekt će se pohraniti u odgovarajući Identity Map objekt. Tada, svaki sljedeći

put kada se ćeli učitati isti entitet, učitati će se iz objekta Identity Map. Prema tome, uzorak dizajna Identity

Map je preporučljivo implementirati u vlastitom ORM sustavu.

Također, trebalo bi dobro razmisliti kako implementirati uzorak dizajna Identity Map u ORM sustavu. ORM

sustavi ne znaju unaprijed s kojim entitetima rade. Jedno moguće rješenje bi bilo kreirati mali podsustav koji

dinamički kreira i registrira odgovarajuće Identity Map objekte i taj podsustav omotati s jednostavnijim

sučeljem [uzorak dizajna Facade (Gamma et al., 1995:185)].

Page 66: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

62

6.7. Query Object

Uzorak dizajna Query Object nije toliko obavezan za ORM sustav, no njegova implementacija je

korisna. Pogotovo ako korisnik tog ORM sustava ne poznaje sintaksu SQL upita, ali zna raditi s objektima.

Razlog njegovog navođenja kao uzorka dizajna primjeren za ORM sustave je što JPA daje na raspolaganje

sličan API - Criteria API.

Pomoću Criteria API formiraju se upiti kao objekti, a ti upitni objekti se onda koriste kao upiti prema bazi

podataka (Oracle, 2013:661). U ovom radu za primjer implementirao se relativno jednostavan primjer uzorka

dizajna Query Object, no za vlastiti ORM sustav implementacije može biti znatno komplicirana. Na temelju

primjera za Criteria API (Oracle, 2013:661-671) može se vidjeti koliko komplicirano, ali učinkovito, Query

Object može biti implementiran.

6.8. Unit of Work

Glavni razlog navođenja ovog uzorka dizajna kao uzorka koji bi bio primjenjiv u nekom vlastitom

ORM sustavu je što se u korisničkoj dokumentaciji za Hibernate ORM (Mihalcea et al., 2017, 1. Architecture)

navodi da je objekt Session, koji je u JPA ekvivalentan objektu EntityManager, konceptualno modeliran

prema uzorku dizajna Unit of Work kojeg Fowler opisuje.

Ti objekti služe za bilježenje učitanih i novokreiranih objekata entiteta i omogućuju brisanje tih objekata kao

i njihovo ažuriranje. U neku ruku, ti objekti implementiraju i uzorak dizajna Facade (Gamma et al., 1995:185)

tako da pruža sučelje samo za osnovne operacije.

Page 67: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

63

7. Refaktoriranje podatkovnog sloja

Fowler (1999:53-54) koristi dvije definicije za definiranja pojma refaktoriranja. Jedna definicija

opisuje pojam refaktoriranja kao imenice, a druga definicija opisuje pojam refaktoriranja kao glagola. Kao

imenica, refaktoriranje je izmjena u unutrašnjoj strukturi programa (moglo bi se reći i "izmjena u

programskom kodu") koja ne mijenja njegovo vanjsko ponašanje, ali je čini razumljivijom i lakšom za

izmijeniti. Kao glagol, refaktoriranje znači restrukturirati program uvođenjem niza refaktoriranja (imenica)

bez mijenjanja njegovog vanjskog ponašanja.

Na temelju tih dviju definicija mogu se izvući dva moguća ključna pojma: 1) "izmjena unutarnje strukture" i

2) "neizmijenjeno vanjsko ponašanje." Prvi ključni pojam bi bila aktivnost koja se provodi refaktoriranjem,

a drugi pojam bi bio ograničenje na tu aktivnost. Odnosno, na temelju toga refaktoriranje bi bila aktivnost

izmjene programskog koda aplikacije, ali tako da se održi njeno izvorno ponašanje. Pitanje je: zašto mijenjati

programski kod ako ponašanje ostaje isto? Odgovor na to pitanje sadržano je u definiciji pojma refaktoriranja

kao imenice i Fowler (1999:54) također to naglašuje u svojoj knjizi: kako bi programski kod bio čitljiviji za

druge programere i kako bi se lakše mogao izmijeniti, ili čak nadograditi, u budućnosti. Ako je "izmjena

unutarnje strukture" aktivnost i "neizmijenjeno vanjsko ponašanj" ograničenje, onda bi se moglo reći da je

"čitljiviji i lakše izmjenjivi koda" rezultat refaktoriranja.

Treba napomenuti da se refaktoriranje ne poistovjećuje s uzorcima dizajna. Uzorci dizajna rješavaju probleme

oko dizajna arhitekture računalnog sustava. Na primjer, uzorak dizajna Singleton, kojeg opisuju Gamma et

al. (1995), omogućuje da se neki objekti instanciraju samo jednom u životnom ciklusu aplikacije i omogućava

globalni pristup do tih objekata. Refaktoriranja se primjenjuju kako bi se programski kod računalnog sustava

učinio čitljivijim i lakše izmjenjivim. Svako refaktoriranje opisano u Fowlerovoj knjizi (1999) sadrži listu

koraka kako da se sigurno provedu. Na primjer, refaktoriranje Extract Method služi za izvlačenje fragmenta

programskog koda u zasebnu metodu.

Refaktoriranje podatkovnog sloja može se podijeliti u dva dijela: refaktoriranje programskog koda na razini

podatkovnog sloja i refaktoriranje baze podataka. U kontekstu refaktoriranja programskog koda,

refaktoriranje bi se provodilo nad objektima koji predstavljaju podatke, odnosno podatkovne objekte, i na

druge, ne-podatkovne, objekte koji na neki način doprinose u radu s podatkovnim objektima (npr. Data

Mapper objekti koji olakšavaju preslikavanje objekata između aplikacije i baze podataka). U kontekstu

refaktoriranja baze podataka, refaktoriranje se provodi uglavnom nad samom bazom podataka, Ono ne

obuhvaća samo tablice, već i refaktoriranje drugih aspekata baza podataka, poput procedura, okidača, itd.

7.1. Refaktoriranje programskog koda

Kao što je rečeno, refaktoriranje programskog koda u podatkovnom sloju uglavnom se odnosi na

podatkovne objekte te pomoćne objekte koji na neki način doprinose podatkovnom sloju aplikacije. Klase

tih podatkovnih objekata uglavnom se sastoje od privatnih polja, te za svako polje postoji metoda koja

dohvaća vrijednost tog polja i metoda koja postavlja vrijednost tog polja. No, Fowler (1999:86-87) takve

klase smatra "glupim nositeljima vrijednosti" (eng. dumb data holders) koje bi trebalo izmijeniti kako bi im

Page 68: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

64

se dodala vlastita odgovornost.

U četvrtom i petom poglavlju često su se koristili "glupi nositelji vrijednosti" kako bi se prikazao primjer

implementacije raznih uzoraka dizajna vezanih za temu ovog rada. Kao primjer provođenja refaktoriranja na

jednom takvom podatkovnom objektu, uzet će se primjer napisan za uzorak dizajna Data Mapper i

refaktorirati. Primjer refaktoriranja će biti jednostavan i pokazati će se refaktoriranje samo na metodama koje

postavljaju vrijednosti parametara za upit. Također, kako bi se skratila priča prikazati će se samo programski

kod klasa prije refaktoriranja i programski kod klasa nakon refaktorianja.

Primjer koda 7.1.1. pokazuje klasu Employee koja predstavlja podatkovnu klasu i primjer koda 7.1.2.

prikazuje klasu EmployeeMapper, odnosno njene metode za postavljanje vrijednosti upita.

Primjer koda 7.1.1. Klasa Employee prije refaktoriranja

public class Employee {

private long id;

private String name;

private String surname;

// Getter i setter metode

}

Primjer koda 7.1.2. Klasa EmployeeMapper prije refaktoriranja

public class EmployeeMapper extends AbtractMapper<Employee> {

// ...

@Override

protected void setCreateStatementValues(Employee obj, PreparedStatement ps)

throws SQLException {

ps.setString(1, obj.getName());

ps.setString(2, obj.getSurname());

}

@Override

protected void setUpdateStatementValues(Employee obj, PreparedStatement ps)

throws SQLException {

ps.setString(1, obj.getName());

ps.setString(2, obj.getSurname());

ps.setLong(3, obj.getID());

}

@Override

protected void setDeleteStatementValues(Employee obj, PreparedStatement ps)

throws SQLException {

ps.setLong(1, obj.getID());

}

// ...

}

Page 69: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

65

Kao što se vidi u primjeru koda 7.1.2., klasa EmployeeMapper često koristi metode za dohvaćanje vrijednosti

polja iz objekta Employee kako bi se postavili vrijednosti upita. Odgovornost postavljanja vrijednosti upita

bi se lagano mogla prebaciti u klasu Employee. Kako bi se to napravilo primijeniti će se refaktoriranje Extract

Method (Fowler et al., 1999:110) za svaku metodu iz primjera 7.1.2. i onda će se primijeniti refaktoriranje

Move Method (Fowler et al., 1999:142) kako bi se te metode prebacila u klasu Employee. Postojeće metode

iz klase EmployeeMapper će se prilagoditi tako da pozivaju nove metode iz objekata klase Employee.

Primjer koda 7.1.3. pokazuje klasu Employee i primjer koda 7.1.4. prikazuje klasu EmployeeMapper, nakon

provođenog refaktoriranja.

Primjer koda 7.1.3. Klasa Employee nakon refaktoriranja

public class Employee {

private long id;

private String name;

private String surname;

// Getter i setter metode

public void setCreateStatementValues(PreparedStatement ps)

throws SQLException {

ps.setString(1, getName());

ps.setString(2, getSurname());

}

public void setUpdateStatementValues(PreparedStatement ps)

throws SQLException {

ps.setString(1, getName());

ps.setString(2, getSurname());

ps.setLong(3, getID());

}

public void setDeleteStatementValues(PreparedStatement ps)

throws SQLException {

ps.setLong(1, getID());

}

}

Primjer koda 7.1.4. Klasa EmployeeMapper nakon refaktoriranja

public class EmployeeMapper extends AbtractMapper<Employee> {

// ...

@Override

protected void setCreateStatementValues(Employee obj, PreparedStatement ps)

throws SQLException {

obj.setCreateStatementValues(ps);

}

@Override

protected void setUpdateStatementValues(Employee obj, PreparedStatement ps)

throws SQLException {

Page 70: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

66

obj.setUpdateStatementValues(ps);

}

@Override

protected void setDeleteStatementValues(Employee obj, PreparedStatement ps)

throws SQLException {

obj.setDeleteStatementValues(ps);

}

// ...

}

I time je završeno predviđeno refaktoriranje. Sada, umjesto da objekt klase EmployeeMapper "traži pojedine

informacije od zaposlenika", ono "traži zaposlenika da ispuni formular" i time klasa Employee više nije "glupi

nositelj vrijednosti."

Naravno, treba dobro razmisliti koja refaktoriranja se mogu primijeniti, a koja ne. Odnosno, treba imati na

umu da u određenim slučajevima računalni sustav ne može podržati određena refaktoriranja, Na primjer, ako

računalni sustav koristi postojeći ORM sustav, npr. Hibernate ili EclipseLink, ne može se provesti

refaktoriranje Encapsulate Collection (Fowler, 1999:208). Razlog je što spomenuti ORM sustavi ovise o

metodama za postavljanje i dohvaćanje vrijednosti polja nekog entiteta, a spomenuto refaktorianje

zamjenjuje metodu za postavljanje kolekcije s metodama za dodavanje i brisanje pojedinačnog elementa

kolekcije (npr. metoda setItems() bi bila zamijenjena s metodama addItem() i removeItem()).

7.2. Refaktoriranje baze podataka

Refaktoriranje baza podataka je refaktoriranje koje se provodi nad bazom podataka. Ambler i

Sadalage (2006:14) refaktoriranje baze podataka definiraju kao jednostavna izmjena nad shemom baze

podataka koja poboljšava njen dizajn dok održava njenu bihevioralnu i informacijsku semantiku. U ovoj

definiciji, Ambler i Sadalage (2006:14) podrazumijevaju da "shema baze podataka" uključuje strukturne

aspekte (tablice i pogledi) te funkcionalne aspekte (procedure i okidači) baze podataka.

Jedno od bitnijih razlika između refaktoriranja baze podataka i refaktoriranja programskog koda je u tome

što ovo drugo ne mijenja vanjsko ponašanje aplikacije, dok ovo prvo ne mijenja i ponašanje baze podataka i

mora održavati informacije konzistentnim (Ambler i Sadalage, 2006:15).

Refaktoriranje baze podataka dodatno komplicira stvari u tome što čak i manja refaktoriranja zahtijevaju

provođenje izmjena u aplikaciji koja koristi tu bazu podataka tako da aplikacija može nastaviti normalno

raditi s ažuriranom shemom baze podataka. Koliko refaktoriranje baze podataka komplicira stvari ovisi o

"okolini" u kojoj je smještena. Amber i Sadalage (2006:15) navode sljedeće okoline u kojoj baza podataka

može biti smještena:

1. jedno-aplikacijska okolina za bazu podataka (eng. single-application database environment) i

2. više-aplikacijska okolina za bazu podataka (eng. multi-application database environment).

Jedno-aplikacijska okolina za bazu podataka, prikazana na slici 7.2.1., je najjednostavnija. U ovakvim

Page 71: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

67

okolinama podrazumijeva se da su jedinu aplikaciju koja koristi bazu podataka napravili pojedinci koji i

posjeduju bazu podataka. U tom slučaju, i aplikacija i baza podataka se mogu paralelno refaktorirati i

primijeniti (Amber i Sadalage, 2006).

Slika 7.2.1. Jedno aplikacija okolina za bazu podataka [vlastiti uradak temeljen

na Ambler i Sadalage (2006:16)]

Kod više-aplikacijskih okolina za bazu podataka, prikazano na slici 7.2.2., paralelno refaktoriranje baze

podataka i aplikacija je skoro pa nemoguće. U ovoj okolini postoje razne druge aplikacije koje koriste bazu

podataka nad kojima vlasnik baze podataka nema kontrolu i ne može odmah od njih zatražiti da sinkroniziraju

izmjene koje su nastale refaktoriranjem. U tom slučaju, tijekom refaktoriranja uvodi se "prijelazno razdoblje"

(eng. transition period).

Slika 7.2.2. Više-aplikacijska okolina za bazu podataka [vlastiti uradak temeljen

na Ambler i Sadalage (2006:16)]

Pretpostavimo da se shema baze podataka prije refaktoriranja nalazi u početnom stanju, a nakon

refaktoriranja nalazi se željenom stanju. Tijekom prijelaznog razdoblja shema baze podataka nalazi se

Page 72: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

68

istovremeno i u početnom i u željenom stanju. Na taj način aplikacije koje jesu refaktorirane zajedno s bazom

podataka mogu koristiti željeno stanje baze podataka, a aplikacije koje nisu refaktorirane mogu koristiti

početno stanje baze podataka. Na prvi pogled, ovo se može činiti zbunjujuće, ali je u stvari veoma

jednostavno za shvatiti. Najbolje bi bilo prikazati kako funkcionira prijelazno razdoblje uz primjer.

Primjer na slici 7.2.3. prikazuje usporedni ER dijagrami za tablicu client kada se nad njom primijeni

refaktoriranje Rename Table (Ambler i Sadalage, 2006:113) kako bi se tablica preimenovala u customer. Za

ovo refaktoriranje potrebno je kreirati novu tablicu s željenim imenom i s istom shemom kao tablica client.

Nakon toga, potrebno je sve podatke prebaciti iz tablice client u drugu tablicu. Na kraju refaktoriranja briše

se stara tablica. U prijelaznom razdoblju obje tablice će biti prisutne u bazi podataka.

Slika 7.2.3. Provođenje Rename Table refaktoriranja

Jedan problem kod provođenja refaktoriranja Rename Table je sinkroniziranje tih dviju tablica tako da se

Page 73: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

69

operacija kreiranja, ažuriranja i brisanja redova iz jedne tablice preslika u drugu tablicu. Rješenje takvog

problema je uvođenje okidača na obje tablice koja će tu operaciju ponoviti u drugoj.

Još jedan važan aspekt prijelaznog razdoblja je određivanje duljine trajanja tog razdoblja. Nakon što prođe

to razdoblje, sve što je ostalo od stare baze podataka se briše. Ambler i Sadalage (2006:18) navode kako bi

prijelazno razdoblje trebalo trajati minimalno jednu i pol godine kako bi ostali razvojni timovi imali vremena

ažurirati svoje aplikacije tako da mogu koristiti novu shemu baze podataka.

Postoji i način kojim bi se omogućilo drugim aplikacijama korištenje refaktorirane sheme baze podataka bez

potrebe za uvođenjem prijelaznog razdoblja. Učahuri se pristup bazi podataka (Ambler i Sadalage, 2006:27).

Ambler i Sadalage (2006:27) da takvo učahurivanje može implementirati pomoću posebnim objektima za

pristup podacima (eng. data access objects), procedurama iz baze podataka ili čak s pomoću Web servisa.

Page 74: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

70

8. Aplikacija

U sklopu ovog diplomskog rada napravljena je i aplikacija. Glavni cilj za izradu ove aplikacije nije

razvoj potpune aplikacije koja bi bila spremna za korištenje u produkciji, već je razvoj primjera aplikacije

koja koristi neke od uzoraka dizajna koji su opisani u poglavljima 4. Uzorci dizajna za podatkovni sloj i 5.

Uzorci dizajna za rad s bazom podataka.

U ovom poglavlju opisati će se što aplikacija radi, spomenuti će se tehnologije koje su korištene za njen

razvoj, prikazati struktura baze podataka u obliku ER dijagrama i objasniti, prikazati će se klase entiteta koji

se koriste u aplikaciji u obliku dijagrama klasa i objasniti i navesti će se korišteni uzorci dizajna te prikazati

će se njihove implementacija putem dijagrama klasa i/ili programskog koda. Opis aplikacije neće biti znatno

detaljan jer, u kontekstu njenog korištenja, radi se o jednostavnoj aplikaciji.

8.1. Opis aplikacije

Radi se o minimalističkoj Web aplikaciji za upravljanje ljudskim resursima. Kao "uzor" i "inspiracija

za ideju" bila je OrangeHRM4, besplatna Web aplikacija s istom namjenom, ali znatno potpunija u kontekstu

funkcionalnosti.

Ovakva vrsta aplikacije je odabrana jer pretežito radi s podacima: kreira nove podatke, ažurira i briše

postojeće podatke, povezuje manje podatke (status zaposlenja, vještine, posao, itd.) u jedan veći podatak

(zaposlenik). Zato je takva vrsta aplikacije savršena za prikaz primjene uzoraka dizajna za podatkovni sloj.

Za ovu aplikaciju definirani su sljedeći entiteti za koje korisnik ima slobodu kreirati, brisati te ažurirati:

• zaposlenik,

• organizacijska jedinica tvrtke,

• posao,

• status zaposlenja (zaposlen, nezaposlen, itd.),

• vještina zaposlenika,

• licenca (npr. licenca za korištenje IntelliJ IDEA Ultimate razvojno okruženje),

• stručno osposobljavanje (u aplikaciji skraćeno na "trening", tj. training),

• kupac/klijent i

• projekt.

Većina navedenih entiteta služe kao atributi za entitet zaposlenika, osim entiteta kupca/klijenta koji se

uglavnom koristi kao informacija o tome tko je vlasnik projekta. No, korisnik ima slobodu kreiranja, brisanja

i ažuriranja svakog od navedenih entiteta.

4https://www.orangehrm.com/

Page 75: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

71

8.2. Korištene tehnologije

Ova sekcija poglavlja dijeli se u tri podređene sekcije: integrirano razvojno okruženje (IDE), Web

poslužitelj, razvojni okvir i baza podataka.

8.2.1. Integrirano razvojno okruženje (IDE)

Za integrirano razvojno okruženje (eng. integrated development environment, IDE) korišten je

Netbeans 8.2. To razvojno okruženje može se koristiti za razvoj raznovrsnih stolnih i Web aplikacija u

programskom jeziku Java i Java EE, respektivno. Također sadrži module za razvoj C/C++ aplikacija, podršku

za HTML, CSS i JavaScript te module za razvoj Web aplikacija u PHP jeziku.

Za aplikaciju u sklopu diplomskog rada koristio se samo modul za razvoj Java EE Web aplikacija.

8.2.2. Razvojni okvir

Za razvojni okvir (eng. framework) korištena je JavaServer Faces (JSF) tehnologija za Java EE. JSF

je razvojni okvir za razvoj Web aplikacija čiji je glavni fokus razvoj korisničkog sučelja (Oracle, 2013:59).

Ona omogućuje korištenje Facelets tehnologije za generiranje Web stranica (Oracle, 2013:60) i posebnih

vrsta zrna zvanih Managed Bean kojom se implementiraju operacije na strani poslužitelja koje poziva klijent

(preko stranica generiranih s Facelets).

JSF je primarno korišten za razvoj prezentacijskog sloja aplikacije koja poziva određene poslovne metode

kojima se kreiraju, ažuriraju i brišu podaci iz podatkovnog sloja..

8.2.3. Web poslužitelj

Za ovu aplikaciju potreban je Web poslužitelj koji podržava JSF tehnologiju prikaza Web stranica.

Postoje tri, besplatna, kandidata: Oracle Glassfish, Apache TomEE i Wildfly. Sva tri kandidata imaju svoje

prednosti i mane, a napravljena aplikacija bi lagano radila sa sva tri poslužitelja.

Na početku razvoja aplikacije bio je odabran Oracle Glassfish. No, pred krajem razvoja poslužitelj je počeo

povremeno izbacivati greške koje nisu mogle biti riješene sa strane razvoja aplikacije. Pod povremeno misli

se da bi ponekad izbacio tu specifičnu grešku, a ponekad bi aplikacija normalno radila.

Zbog toga, odlučilo se Web aplikaciju prenijeti na drugi Web poslužitelj: Apache TomEE. Netbeans 8.2. IDE

nema podršku za kreiranje EJB modula za Apache TomEE, pa se cijela Web aplikacija spojila u jedan projekt.

Greške se više nisu pojavljivale i razvoj se znatno ubrzao zbog toga što je Apache TomEE veoma brzo mogao

kompilirati kod Web aplikacije i pokrenuti je.

Ukratko, za Web poslužitelj koristi se Apache TomEE.

8.2.4. Sustav za upravljanje bazom podataka

Za ovu Web aplikaciju nije bila zamišljena mogućnost fleksibilne komunikacije s različitim

sustavima za upravljanje bazama podataka (SUBP). Naravno, to može dovesti do problema gdje treba

prilagoditi "rukom pisane" upite na specifičan način ako korišteni SUBP koristi neki svoj žargon.

No, to nije problem u ovoj aplikaciji jer svi "rukom pisani" upiti u njoj su oni upiti čija je sintaksa jednaka

Page 76: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

72

kod svih ostalih baza podataka (to se ugkavnom misli na SELECT, UPDATE i DELETE upite). Također, sve

tablice moraju biti unaprijed pripremljene za ovu aplikaciju, inače neće funkcionirati.

Odlučilo se na korištenje Apache Derbi sustava za upravljanje bazom podataka.

8.3. Struktura baze podataka

Struktura baze podataka korištena u aplikaciji prikazana je u obliku ER dijagrama na slici 8.3.1.

Sastoji se od osam relacijskih tablica koje predstavljaju konkretne entitete i četiri pomoćnih tablica koje

postoje samo radi implementacije veze više-više između određenih entiteta.

Nadalje, svaka zasebni entitet (osim onih koje implementiraju vezu više-više) iz baze podataka biti će opisan

u zasebnom, podređenom, poglavlju. Svaki opis entiteta opisivati će što taj entitet predstavlja te pojasniti

njegovu vezu s onim entitetima s kojima je povezan.

Page 77: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

73

Slika 8.3.1. ER dijagram baze podataka

Također, treba spomenuti da svaka relacijska tablica, koja predstavlja konkretni entitet, sadrži atribut id kao

cjelobrojni primarni ključ.

8.3.1. Entitet employee

Entitet employee prestavlja zaposlenika i ono se može smatrati glavnim podatkom koji se koristi u

aplikaciji. Osnovni podaci koji opisuju ovaj entitet su ime i prezime zaposlenika (atributi first_name i

last_name), iznos i valuta njegove plaće (atributi salary_amount i salary_currency) te početak i kraj radnog

vremena (atributi working_hour_start i working_hour_end).

Page 78: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

74

Iduća tri atributa su vanjski ključevi koji referenciraju retke iz tablica employment_status,

organizational_unit i job. Atribut employment_status referencira redak iz relacijske tablice

employment_status i opisuje trenutni status zaposlenja zaposlenika (zaposlen, nezaposlen, itd.). Atribut

organizational_unit referencira redak iz relacijske tablice organizational_unit i opisuje kojoj organizacijskoj

jedinici pripada zaposlenik. Atribut job referencura redak iz relacijske tablice job i predstavlja naziv posla,

odnosno poslovnu titulu koja je dodijeljena zaposleniku.

Entitet employee nalazi se u vezi više-više sa sljedećim relacijskim tablicama: skill, training, license i project.

S relacijskom tablicom, odnosno entitetom, skill opisuju se koje vještine posjeduje zaposlenik. S entitetom

training opisuje se koja stručna osposobljavanja je zaposlenik položio i može se navesti i datum početka

polaganja te datum završetka polaganja. S entitetom license opisuje se koje licence su dodijeljene zaposleniku

i može se navesti datum dodijele licence. S entitetom project opisuje se kojim projektima je zaposlenik

dodijeljen.

8.3.2. Entitet organizational_unit

Entitet organizational_unit predstavlja organizacijsku jedinicu tvrtke, odnosno organizacije. Osim

primarnog ključa, atribut sadrži još tri atributa. Prvi atribut, name, predstavlja naziv organizacijske jedinice.

Drugi atribut, description, predstavlja opis te organizacijske jedinice. Treći atribut, superordinate, je

rekurzivna veza jedan-više entiteta organizational_unit sa samim sobom i ono predstavlja nadređenu

organizacijsku jedinicu koju bilo koja organizacijska jedinica može imati.

Osim rekurzivne veze sa samim sobom, entitet organizational_unit se također nalazi u vezi jedan-više s

entitetom employee, gdje se entitet zaposlenika na strani više. To znači da employee sadrži vanjski ključ koji

referencira zapis iz entiteta organizational_unit.

8.3.3. Entitet job

Entitet job predstavlja posao, odnosno poslovnu titulu, koja može biti dodijeljena bilo kojem

zaposleniku. Uz atribut primarnog ključa, sadrži i još dva atributa. Prvi atribut, name, predstavlja naziv posla,

odnosno naziv poslovne titule. Drugi atribut, description, predstavlja opis tog posla.

Nalazi se u vezi jedan-više s entitetom employee, gdje se entitet zaposlenika na strani više. To znači da

employee sadrži vanjski ključ koji referencira jedan podatak iz entiteta job.

8.3.4. Entitet employment_status

Entitet employment_status predstavlja status zaposlenja koje može biti dodijeljeno bilo kojem

zaposleniku. Osim atributa primarnog ključa, sadrži i još dva atributa. Prvi atribut, name, predstavlja naziv

status zaposlenja, a drugi atribut, description, služi za opis statusa zaposlenja.

Nalazi se u vezi jedan-više s entitetom employee, gdje se entitet zaposlenika na strani više. To znači da

employee sadrži vanjski ključ koji referencira zapis iz entiteta organizational_unit.

8.3.5. Entitet skill

Entitet skill predstavlja vještinu koju može posjedovati bilo koji zaposlenik. Slično kao i većini

Page 79: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

75

entiteta, entitet skill sadrži atribut primarnog ključa i još dva dodatna atributa. Prvi dodatni atribut, name,

predstavlja naziv vještine, a drugi atribut, description, predstavlja opis te vještine.

Nalazi se u vezi više-više s entitetom employee i ta veza je realizirana pomoću relacijske tablice

employee_skill.

8.3.6. Entitet training

Entitet training predstavlja stručno osposobljavanje koje može biti dodijeljeno bilo kojem

zaposleniku da je položio. Osim atributa primarnog ključa, sadrži i atribut name koje predstavlja naziv

stručnog osposobljavanja i atribut description koje opisuje to stručno osposobljavanje.

Nalazi se u vezi više-više s entitetom employee i tu vezu realizira u relacijskoj tablici employee_training.

Spomenuta tablica sadrži dodatne atribute koji opisuju kojeg datuma je započeto stručno osposobljavanje

koje je pridruženo zaposleniku te kojeg datuma je isto stručno osposobljavanje završilo.

8.3.7. Entitet license

Entitet license predstavlja licencu koja može biti dodijeljena bilo kojem zaposleniku. Uz atribut

primarnog ključa, entitet sadrži i atribut name koji predstavlja naziv licence i atribut description koja služi

kao kratak opis licence.

Ovaj entitet se nalazi u vezi više-više s entitetom employee i ona je realizirana pomoću tablice

employee_license. Ta tablica također sadrži atribut koji opisuje kada je licenca dodijeljena zaposleniku.

8.3.8. Entitet customer

Entitet customer predstavlja nekog kupca ili klijenta. Uz primarni ključ sadrži i atribut name koji

predstavlja naziv klijenta (može biti osoba ili tvrtka), atribut address koji predstavlja adresu klijenta, atribut

email koji predstavlja e-mail adresu i atribut phone koji sadrži broj telefona od klijenta.

Ovaj entitet se nalazi u vezi jedan-više s entitetom project, gdje se project nalazi na strani više i sadrži vanjski

ključ koji referencira zapisa iz relacijske tablice customer.

8.3.9. Entitet project

Entitet project predstavlja projekt koji je pokrenut na zahtjev nekog klijenta ili vlastite organizacije.

Uz atribut primarnog ključa, sadrži atribut name koji projektu daje naziv i atribut customer koji povezuje

projekt s klijentom koji ga je pokrenuo na zahtjev.

Ovaj entitet se nalazi u vezi više-više s entitetom employee i ta veza je realizirana pomoću tablice

employee_project.

Također, ovaj entitet se nalazi i u vezi jedan-više s entitetom customer, gdje se ono nalazi na strani više. Ta

veza je realizirana pomoću vanjskog ključa u atributu customer, koji pokazuje na zapis iz relacijske tablice

customer.

Page 80: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

76

8.4. Klase entiteta

Slika 8.4.1. prikazuje dijagram klasa koji prikazuje klase entiteta, apstraktnu klasu Entity te dodatne,

pomoćne, klase koje su korištene od strane klasa entiteta. Svaka od prikazanih klasa entiteta odgovara jednoj

relacijskoj tablici (ne uključujući tablice koje postoje samo da se implementira veza vuše-više između drugih

tablica) prikazanoj na slici 8.3.1. u poglavlju 8.3. Struktura baze podataka.

U ovom dijelu poglavlja opisati će se apstraktna klasa Entity, odnosno kakvu ulogu ona ima u Web aplikaciji,

i opisati će se svaka pojedina klasa entiteta. Opis klase entiteta također će uključivati opis dodatnih, pomoćnih,

klasa, tj. opisati će se za što i zašto se one koriste u klasama entiteta koje se opisuju.

Page 81: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

77

Slika 8.4.1. Dijagram klasa za klase entiteta i pomoćnih klasa

Dodatne i pomoćne klase su na slici 8.4.1. označene svijetlom sivom bojom kako bi se razlikovale od ostalih

klasa koje će biti opisane u ovom poglavlju. Također treba napomenuti da u dijagramu klasa nisu prikazane

metode za dohvaćanje i postavljanje vrijednosti polja jer bi te metode učinile dijagram klasa prevelikim.

8.4.1. Apstraktna klasa Entity

Apstraktna klasa Entity sadrži polje koje sadrži vrijednost primarnog ključa. Spomenuto je u

poglavlju 8.3. Struktura baze podataka kako su svi primarni ključevi cjelobrojni, prema tome je i polje u

klasu Entity cjelobrojnog tipa. Glavni razlog postojanje ove klase je dodjeljivanje svim podatkovnim klasama

zajednički tip podatka. Ova apstraktna klasa omogućuje fleksibilnu implementaciju uzoraka dizajna kao što

su Data Mapper i Identity Map koji ovise o klasi objekata s kojima rade.

8.4.2. Klasa Employee

Klasa Employee predstavlja entitet zaposlenika i tijekom preslikavanja objekti te klase rade s

relacijskom tablicom employee. Kada bi se usporedila relacijska tablica employee s klasom Employee

primijetilo bi se nekoliko razlika. Jedna od tih razlika je što su polja salary_amount i salary_currency iz

tablice zamijenjeni objektom tipa Money, razlog tome što je klasa Money u stvari je implementacija uzorka

dizajna Embedded Value.

Također, klasa Employee sadrži dva polja tipa CustomDate. Klasa CustomDate nije implementacija ikojeg

opisanog uzorka dizajna, već je samo pomoćna klasa koja pomaže u radu s datumima. Specifično, pomaže

da se datum može učitati kao String ili java.sql.Date objekt i da se može pretvoriti opet ili u String ili u

java.sql.Date objekt.

Još jedna razlika se može primijetiti u tome što klasa Employee ne koristi direktno objekte klasa License i

Training nego preko klasa AcquiredLicense i ScheduledTraining. Razlog tome je što je zamišljeno da svako

objekt klase entiteta sadrži samo podatke koji se nalaze u odgovarajućoj relacijskoj tablici. No, to znači da

podaci koji su definirani u asocijativnim tablicama employee_license i employee_training nemaju gdje biti u

aplikaciji. Zato su definirane spomenute pomoćne klase: objekt AcquiredLicense omotava jedan objekt

License s objektom datuma dodjele to licence, a objekt ScheduledTraining omotava objekt Training s

datumskim objektima koji predstavljaju početak polaganja stručnog osposobljavanja i kraj polaganja.

8.4.3. Klasa EmploymentStatus

Klasa EmploymentStatus predstavlja entitet statusa zaposlenja i njeni objektirade s relacijskom

tablicom employment_status. Instance ove klase se dodjeljuju objektima zaposlenika kako bi se opisale

njihov pojedinačan status zaposlenja, poput "zaposlen", "nezaposlen", "na odmoru", itd.

8.4.4. Klasa OrganizationalUnit

Klasa OrganizationalUnit predstavlja organizacijske jedinice neke tvrtke, odnosno organizacije.

Objekti ove klase rade s relacijskom tablicom organizational_unit. Ova klasa se dodjeljuje entitetu

Page 82: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

78

zaposlenika kako bi se dala informacija u kojoj organizacijskoj jedinici je zaposlenik uvršten.

Može se primijetiti da klasa sadrži jedan dodatno polje u usporedbi s relacijskom tablicom, a to je polje

subordinates (hrv. podređeni). Kako polje superordinate (hrv. nadređeni) daje informaciju o tome koja je

nadređena organizacijska jedinica, polje subordinates je obratno – daje popis podređenih organizacijskih

jedinica.

8.4.5. Klasa Job

Klasa Job predstavlja entitet posla, odnosno poslovne titule. Objekti te klase rade s relacijskom

tablicom job. Dodjeljuje se objektima entiteta zaposlenika kako bi se dala informacija koju poslovnu titulu

ima zaposlenik.

8.4.6. Klasa Skill

Klasa Skill predstavlja entitet vještine i njeni objekti rade s relacijskom tablicom skill. Objekt

zaposlenika sadrži popis vještina. Budući da su entiteti zaposlenika i vještina u vezi više-više, tijekom

preslikavanja podataka o zaposleniku mora se gledati koje vještine su pridružene zaposleniku u relacijskoj

tablici employee_skill u bazi podataka.

8.4.7. Klasa License

Klasa License predstavlja entitet licence i njeni objekti rade s relacijskom tablicom license. Entiteti

zaposlenika i licenci nalaze se u vezi više-više, što znači da aplikacija tijekom preslikavanja podataka o

zaposleniku mora gledati koje licence su dodijeljene tom zaposleniku u relacijskoj tablici employee_license

iz baze podataka.

No, objekti klase Employee ne sadrže direktno objektno klase License, već ih drže omotane u objektima klasa

AcquiredLicense. Razlog tome je što objekti klase License ne sadrže informacije o datumu dodijele licence

koja se nalazi u tablici employee_license jer oni sadrže podatke samo iz tablice License. Zato je definirana

klasa AqcuiredLicense čiji objekti će omotati objekt klase License s datumom dodijele te klase i dodijeliti ih

zaposlenicima.

8.4.8. Klasa Training

Klasa Training predstavlja entitet stručnog osposobljavanja. Objekti te klase rade s relacijskom

tablicom training. Entiteti stručnog osposobljavanja i zaposlenika nalaze se u vezi više-više, što znači da

aplikacija tijekom preslikavanja podataka o zaposleniku mora gledati koja stručna osposobljavanja su

pridružena tom zaposleniku u relacijskoj tablici employee_training.

Kao i u slučaju klase License, klasa Employee također ne sadrži direktno objekte klase Training, već ih drže

omotane u objektima klase ScheduledTraining. Razlog tome je što objekti klase Training drže samo one

informacije koje se nalaze u relacijskoj tablici training, a što dovodi do toga da se gube informacije koje se

nalaze u dodatnim poljima asocijativne tablice employee_training. Zato je definirana klasa

ScheduledTraining čiji objekti omotavaju objekte klase Training s datumskim objektima koji predstavljaju

početak i kraj polaganja stručnog osposobljavanja, i takve omotane objekte dodijeliti zaposlenicima.

Page 83: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

79

8.4.9. Klasa Customer

Klasa Customer predstavlja entitet kupca/klijenta i njeni objekti rade s relacijskoj tablicom customer.

Objekti ove klase se dodjeljuju objektima klase Project kako bi se naznačilo koji klijent je razlog pokretanja

projekta.

8.4.10. Klasa Project

Klasa Project predstavlja entitet projekta kojeg je pokrenuo neki klijent i njeni objekti rade s

relacijskom tablicom project. Entiteti projekta i zaposlenika nalaze se u vezi više-više, što znači da tijekom

preslikavanja podataka u objekt zaposlenika aplikacija treba gledati koji projekti su dodijeljeni tom

zaposleniku u relacijskoj tablici employee_project.

8.5. Korišteni uzorci dizajna

U ovom dijelu poglavlja opisati će se uzorci dizajna koji su korišteni u aplikaciji. Za svaki uzorak

dizajna ukratko će se objasniti zašto su oni korišteni te će se prikazati njihova implementacija pomoću

dijagrama klasa i/ili programskog koda. Od opisnih uzoraka dizajna u poglavljima 4. Uzorci dizajna za

podatkovni sloj i 5. Uzorci dizajna za rad s bazom podataka, u aplikaciji se koriste sljedeći:

• Data Mapper,

• Identity Map,

• Embedded Value,

• Value Object i

• Lazy Load.

Također, korišteni su uzorci dizajna Foreign Key Mapping i Association Table Mapping, ali oni neće biti

opisani jer se smatra da su ti uzorci dizajna "opća praksa" u radu s bazom podataka.

8.5.1. Uzorak dizajna Data Mapper

Uzorak dizajna Data Mapper korišten je kako bi se implementirao mehanizam preslikavanja podataka

između objekata i baze podataka. Sav temeljni mehanizam je implementiran je u apstraktnoj klasi

DataMapper, koji je također korišten za primjer uzorka Data Mapper u poglavlju 5.2. Data Mapper. Slika

8.5.1. prikazuje dijagram klasa koji prikazuje implementaciju uzorka Data Mapper u aplikaciji.

Apstraktna klasa DataMapper je također generička klasa, ali sve njene implementacije ograničene su klase

koje nasljeđuju apstraktnu klasu Entity. Jedan razlog za to je osiguravanje da implementacija te apstraktne

klase koristi isključivo klasu entiteta. Drugi razlog tome je što metode create(), odnosno doCreate(),

koristi metodu setId() iz klase Entity kako bi se odmah nakon kreiranja podatka u bazi podataka postavila

vrijednost njegovog primarnog ključa koju je generirala baza podataka.

Page 84: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

80

Slika 8.5.1. Dijagram klasa za implementirani uzorak dizajna Data Mapper

Također, primijeti se postojanje metode map() koja vraća Identity Map objekt za odgovarajući tip entiteta.

Taj Identity Map objekt se primjenjuje u tri slučaja:

• tijekom kreiranja gdje dodaje novi objekt entiteta u mapu,

• tijekom brisanja gdje se briše objekt entiteta iz mape,

• tijekom čitanja podatka gdje se provjerava postoji li već traženi objekt entiteta unutar mape.

8.5.2. Uzorak dizajna Identity Map

Uzorak dizajna Identity Map se koristi kako bi se spriječilo učitavanje dupliciranih objekata entiteta.

Data Mapper objekti korištenu u aplikaciji koriste Identity Map objekte kako bi se provjerilo postoji li već

instanca objekta entiteta u sustavu. Isti Data Mapper objekti također koriste Identity Map objekte tijekom

kreiranja (gdje novo kreirani objekt odmah ulazi u mapu) i brisanja (gdje se objekt koji se želi obrisati miče

iz mape).

U aplikaciji postoji dretva koja, u određenom vremenskom intervalu, briše sadržaj svih Identity Map objekata

kako bi se privremeno oslobodio prostor u memoriji.

Primjer koda 8.5.1. pokazuje implementaciju uzorka dizajna Identity Map u aplikaciji. Ista implementacija

Page 85: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

81

je prikazana u primjeru tog uzorka u poglavlju 4.2. Identity Map.

Primjer koda 8.5.1. Klasa koja implementira uzorak dizajna Identity Map

public class IdentityMap<T extends Entity> {

protected Map<Long, T> entities = new HashMap<>();

public void add(T entity) {

if (entity.getId() != null)

entities.put(entity.getId(), entity);

}

public void remove(Long id) {

entities.remove(id);

}

public boolean contains(Long id) {

return entities.containsKey(id);

}

public void clear() {

entities.clear();

}

public List<T> filter(Predicate<T> predicate) {

List<T> filteredEntities = new ArrayList<>();

entities.forEach((id, entity) -> {

if (predicate.test(entity)) {

filteredEntities.add(entity);

}

});

return filteredEntities;

}

}

8.5.3. Uzorak dizajna Embedded Value

Uzorak dizajna Embedded Value korišten je samo u jednom slučaju: da polja salary_amount i

salary_currency spoji u jedan, smislen, objekt. Klasa Money, koja se na ER dijagramu na slici 8.4.1. može

vidjeti da ju koristi klasa Employee.

Tijekom preslikavanja iz baze podataka u objekt ili obratno, objekt koji vrši preslikavanje, objekt klase

EmployeeMapper, je implementiran da vodi računa o tome da spomenuta dva polja spoji u jedan objekt kada

učitava podatke o zaposleniku iz baze podataka i da rastavi objekt u dva polja kada preslikava podatke iz

objekta u bazu podataka.

Klasa Money, koja implementira uzorak dizajna Embedded Value, prikazana je u primjeru koda 8.5.2.

Primjer koda 8.5.2. Klasa Money koja implementira uzorak dizajna Embedded Value

public class Money {

Page 86: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

82

private BigDecimal amount;

private String currency;

public Money(BigDecimal amount, String currency) {

this.amount = amount.setScale(2, RoundingMode.HALF_EVEN);

this.currency = currency;

}

public BigDecimal getAmount() { return amount; }

public String getCurrency() { return currency; }

public void setAmount(BigDecimal amount) {

this.amount = amount.setScale(2, RoundingMode.HALF_EVEN);

}

public void setCurrency(String currency) { this.currency = currency; }

@Override

public String toString() {

return amount.toString() + " " + currency;

}

}

8.5.4. Uzorak dizajna Value Object

Uzorak dizajna Value Object implementiran u apstraktnoj klasi Entity tako da ju koriste svi objekti

entiteta. U aplikaciji, svi objekti entiteta svode svoj identitet na temelju klase kojoj pripadaju i na temelju

vrijednosti primarnog ključa u objektu. U slučaju da dva objekta entiteta pripadaju istoj klasi, imaju istu

vrijednost primarnog ključa, ali se razlikuju prema vrijednosti ostalih polja, onda se pretpostavlja da jedan

od tih objekata predstavlja ažuriranu verziju drugog objekta.

Primjer koda 8.5.3. prikazuje implementaciju uzorka dizajna Value Object u apstraktnoj klasi Entity.

Podsjetnik, Value Object se implementira nadjačavanjem metode equals() i hashCode().

Primjer koda 8.5.2. Klasa Money koja implementira uzorak dizajna Embedded Value

public abstract class Entity {

protected long id;

public long getId() { return id; }

public void setId(long id) { this.id = id; }

public boolean equals(Entity entity) {

return this.getClass().equals(entity.getClass())

&& this.id == entity.id;

}

@Override

public boolean equals(Object obj) {

return obj instanceof Entity && equals((Entity) obj);

}

@Override

Page 87: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

83

public int hashCode() {

int hash = 7;

hash = 53 * hash + (int) (this.id ^ (this.id >>> 32));

hash = 53 * hash + Objects.hashCode(this.getClass());

return hash;

}

}

8.5.5. Uzorak dizajna Lazy Load

Uzorak dizajna Lazy Load primjenjuje se samo u klasama Employee i Organizational

Unit. Kod klase Employee, uzorak dizajna se koristi u metodama koje dohvaćaju listu objekata Skill, listu

objekata Project, listu objekata License omotanih u objektima Acquired

License i listu objekata Training omotanih u objektima ScheduledTraining. Kod klase OrganizationalUnit,

uzorak dizajna se koristi u metodi koja dohvaća popis objekata koji predstavljaju podređene organizacijske

jedinicie.

Razlog primjene uzorka dizajna Lazy Load u klasu Organizational Unit je drugačiji od razloga njegove

primjene u klasi Employee. Za klasu Employee uzorak je primijenjen kako bi se dohvatile liste objekata tek

kada bude potrebno ih prikazati u aplikaciji. Za klasu OrganizationalUnit uzorak se primjenjuje jer je objekt

preslikavanja, OrganizationalMapper, tijekom učitavanja podataka konkretnog objekta ulazio u beskonačnu

rekurziju kada je učitavao njegove podređene organizacijske jedinice. No, ako se učitavanje podređenih

organizacijskih jedinica odgodilo primjenom uzorka Lazy Load, aplikacija nije ulazila u beskonačnu

rekurziju.

Primjer koda 8.5.4. pokazuje primjer primjene uzorka ditajna Lazy Load u metodi getSkills() klase

Employee. U toj metodi koristi se metoda findFormEmployee() iz klase SkillMapper koja pronalazi i

vraća sve objekte klase Skill koji su pridruženi zaposleniku u bazi podataka. Programski kod te metode u

klasi SkillMapper prikazan je u primjeru koda 8.5.5.

Može se primijetiti u primjeru koda 8.5.4. korištenje objekta klase EntityMapper. Ta klasa je zrno sesije bez

stanja (eng. Stateless Session Bean) koji sadrži mapu svih korištenih Data Mapper objekata. Ono će biti

objašnjeno u poglavlju 8.6. EntityMapper i EntityMap.

Primjer koda 8.5.4. Primjena uzorka dizajna Lazy Load u metodi getSkills() klase Employee

public class Employee extends Entity {

// ...

private final EntityMapper entityMapper;

public List<Skill> getSkills() {

if (skills == null) {

SkillMapper skillMapper =

(SkillMapper) entityMapper.getMapper(Skill.class);

skills = skillMapper.findForEmployee(this);

}

Page 88: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

84

return skills;

}

// ...

}

Primjer koda 8.5.5. Metoda za prinalazk i dohvaćanje objekata klase Skill

koji su pridruženi zaposleniku u bazi podataka

public class SkillMapper extends DataMapper<Skill> {

// ...

private static final String FIND_FOR_EMPLOYEE_STATEMENT =

"SELECT s.* FROM skill s, employee_skill es "

+ "WHERE s.id=es.skill AND es.employee=?";

public List<Skill> findForEmployee(Employee employee) {

List<Skill> skills = new ArrayList<>();

try (Connection conn = createConnection();

PreparedStatement ps = conn.prepareStatement(

FIND_FOR_EMPLOYEE_STATEMENT)) {

ps.setLong(1, employee.getId());

try (ResultSet rs = ps.executeQuery()) {

while (rs.next()) {

Skill skill = load(rs);

skills.add(skill);

}

}

} catch (SQLException ex) {

System.out.println("Unable to find skills for an employee ("

+ getClass().getSimpleName() + "): " + ex.getMessage());

ex.printStackTrace(System.out);

}

return skills;

}

// ...

}

8.6. EntityMapper i EntityMap

EntityMapper i EntityMap su zrna sesije (eng. Session Bean) koji se koriste unutar aplikacije. Entity

Mapper je zrno sesije bez stanja, a EntityMap je zrno sesije za kojeg postoji samo jedna instanca u cijeloj

aplikaciji (eng. Singleton Session Bean).

EntityMapper sadrži mapu koja se sastoji objekata koji vrše preslikavanje između objekata i baze podataka,

odnosno sastoji se od različitih objekata čije klase nasljeđuju apstraktnu klasu DataMapper. Glavni naum

ovo zrna sesije je omogućiti aplikaciji da koristi unaprijed instancirane objekte preslikavanja kada je potrebno.

Primjer koda 8.6.1. prikazuje programski kod EntityMapper klase.

Primjer koda 8.6.1. Klasa EntityMapper

Page 89: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

85

@Stateless

@Startup

@LocalBean

public class EntityMapper {

private final Map<Class<? extends Entity>, DataMapper> mappers;

public EntityMapper() {

mappers = new HashMap();

mappers.put(Skill.class, new SkillMapper());

mappers.put(License.class, new LicenseMapper());

mappers.put(EmploymentStatus.class, new EmploymentStatusMapper());

mappers.put(OrganizationalUnit.class, new OrganizationalUnitMapper());

mappers.put(Job.class, new JobMapper());

mappers.put(Customer.class, new CustomerMapper());

mappers.put(Project.class, new ProjectMapper());

mappers.put(Training.class, new TrainingMapper());

mappers.put(Employee.class, new EmployeeMapper());

}

public <T extends Entity> DataMapper getMapper(Class<T> entityClass) {

return mappers.get(entityClass);

}

public <T extends Entity> void create(T entity) {

mappers.get(entity.getClass()).create(entity);

}

public <T extends Entity> void update(T entity) {

mappers.get(entity.getClass()).update(entity);

}

public <T extends Entity> void delete(T entity) {

mappers.get(entity.getClass()).delete(entity);

}

public <T extends Entity> T find(Class<T> entityClass, long id) {

return (T) mappers.get(entityClass).find(id);

}

public <T extends Entity> List<T> findAll(Class<T> entityClass) {

return (List<T>) mappers.get(entityClass).findAll();

}

}

EntityMap sadrži mapu u kojoj se nalaze instance IdentityMap objekata za svaku klasu entiteta. Ovo

omogućuje postojanje samo jednog objekta određene klase entiteta u cijeloj aplikaciji. Također, aplikacija

tijekom pokretanja pokreće i dretvu koja periodički čisti sadržaj svi IdentityMap objekata. Primjer koda 8.6.2.

pokazuje programski kod za klasu EntityMap. Zbog mogućnosti konkurentnog pristupa ovom zrnu sesije

umjesto, običnog HashMap objekta koristi se ConcurrentHashMap i na svim definiranim metodama

pridružena je ključna riječ synchronized.

Page 90: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

86

Primjer koda 8.6.2. Klasa EntityMap

@Singleton

@Startup

@LocalBean

public class EntityMap {

private final Map<Class<? extends Entity>, IdentityMap<?>> maps;

public EntityMap() {

maps = new ConcurrentHashMap<>();

maps.put(Skill.class, new IdentityMap<>());

maps.put(License.class, new IdentityMap<>());

maps.put(EmploymentStatus.class, new IdentityMap<>());

maps.put(OrganizationalUnit.class, new IdentityMap<>());

maps.put(Job.class, new IdentityMap<>());

maps.put(Customer.class, new IdentityMap<>());

maps.put(Project.class, new IdentityMap<>());

maps.put(Training.class, new IdentityMap<>());

maps.put(Employee.class, new IdentityMap<>());

}

public synchronized <T extends Entity>

IdentityMap<T> getMap(Class<T> entityClass) {

return (IdentityMap<T>) maps.get(entityClass);

}

public synchronized <T extends Entity>

List<T> filter(Class<T> entityClass, Predicate<T> predicate) {

return ((IdentityMap<T>) maps.get(entityClass)).filter(predicate);

}

public synchronized void clearAll() {

maps.forEach((entityClass, identityMap) -> identityMap.clear());

}

}

Page 91: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

87

9. Zaključak

U ovom diplomskom radu prošlo se kroz osnovne ideje primjene uzorka dizajna, uključujući zašto

se koriste i kako oni rješavaju probleme u dizajnu. Nakon toga provela se usporedna analiza predložaka za

opis uzoraka dizajna koje su koristili Gamma et al. (1995), Buschmann et al. (1996) i Fowler (2003) u svojim

knjigama o uzorcima dizajna, nakon čega se predstavio vlastiti predložak koji je korišten za opis uzoraka

dizajna u ovom radu. Zatim, iduća dva poglavlja bila su posvećena opisom uzoraka dizajna koji bi se mogli

primijeniti na podatkovni sloj i koji bi se mogli koristiti u radu s bazom podataka. Na temelju opisanih

uzoraka, odredilo koji bi mogli korišteni u razvoju ORM sustava.Nakon toga, govorilo se refaktoriranju

podatkovnoj sloja u dva konteksta: u kontekstu refaktoriranja programskog koda i refaktoriranja baze

podataka. I, na kraju, opisala se aplikacija koja je rađena u sklopu ovog rada, uključujući prikaz i opis

strukture njene baze podataka, prikaz i opis klasa entiteta te opisali su korišteni uzorci dizajna.

Kao i "originalni" uzorci dizajna koje su opisali Gamma i njegovi suradnici (1995) i Fowlerovi uzorci, koji

su opisani u ovom radu i imaju primjenu u podatkovnom sloju aplikacije, mogu olakšati i/ili obogatiti

aplikaciju. Uzorci u ovom radu također daju dobar pogled na razne načine kako se mogu koristiti podaci ili

provoditi operacije s njima. Od svih opisanih uzoraka, za najznačajnije bih odabrao uzorke Data Mapper,

Active Record i IdentityMap. Prva dva uzorka dizajna su uzorci za preslikavanje podataka i oni lijepo

pokazuju kako pojednostaviti provođenje CRUD upita nad bazom podataka. Identity Map pak ukazuje na

problem koji neiskusni programeri često ignoriraju – problem duplikata objekata entiteta – i kako ga riješiti.

Za kraj, izraziti će se isto mišljenje koje imam i za sve ostale vrste uzoraka dizajna: isplati ih se proučiti. Ne

samo kao rješenja problema u dizajnu, već i za bolje razumijevanje objektno-orijentiranog programiranja.

Posebice za pojedince koji se prvi put susreću s paradigmom objektno-orijentiranog programiranja.

Page 92: DIPLOMSKI RAD - bib.irb.hr · dizajna dodijeliti naziv jer se time uspostavlja rječnik uzoraka dizajna, što olakšava komunikaciju između programera (Fowler, 2003:119). Gamma et

88

Literatura

[1] Ambler S. W., Sadalage P. J. (2006) Refactoring Databases: Evolutionary Database Design. Boston:

Addison-Wesley.

[2] Buschmann F., Meunier R., Rohnert H., Sommerlad P., Stal M. (1996) Pattern-Oriented Software

Architecture Volume 1: A System of Patterns. Chichester: John Wiley & Sons.

[3] Fowler M., Beck K., Brant J., Opdyke W., Roberts D. (1999) Refactoring: Improving the Design of

Existing Code. Boston: Addison-Wesley.

[4] Fowler M. (2003) Patterns of Enterprise Application Architecture. Boston: Addison-Wesley.

[5] Gamma E., Helm R., Johnson R., Vlissides J. (1995) Design Patterns: Elements of Reusable Object-

Oriented Software. Boston: Addison-Wesley.

[6] Mihalcea V., Ebersole S., Boriero A., Morling G., Badner G., Cranford C., Bernard E., Grinovero S.,

Meyer B., Ferentschik H., King G., Bauer C., Andersen M. R., Maesen K., Vansa R., Jacomet L. (2017)

Hibernate ORM 5.2.10.Final User Guide. [Online] Dostupno na:

http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_

User_Guide.html (Pristupljeno: 03.08.2017.)

[7] Oracle (2013) The Java EE 6 Tutorial. [Online] Dostupno na: http://docs.oracle.com/

javaee/6/tutorial/doc/javaeetutorial6.pdf (Pristupljeno: 03.08.2017.)