Professional Documents
Culture Documents
Www2 Predavanje 5 Nasledjivanje
Www2 Predavanje 5 Nasledjivanje
Vrlo esto novi programi nastaju proirivanjem prethodnih. Najbolji nain za stvaranje novog softvera je imitacija,
doterivanje i proirivanje postojeeg. Tradicionalni metodi razvoja softvera su zanemarivali ovakvo stanovite. U objektno
orijentisanom programiranju to je osnovni nain rada.
Zamislite sluaj kada imate izvorni kod neke klase. Kako biste mogli da taj kod ponovo iskoristite. Mogli biste da ga
iskopirate i u kopiji menjate ono to je potrebno. Kod tradicionalnih jezika to je bila jedina mogunost. Problem je kako da
sve ostane dobro organizovano i kako da se do kraja razume originalni kod.
Ako biste imali nekoliko desetina klasa i ako je vaem programu potrebno jo nekoliko desetina klasa, na kraju biste
prethodno opisanom tehnikom kopiranja stigli do vie desetina datoteka sa izvornim kodom. Bez paljivog planiranja
zavrili biste sa neorganizovanom gomilom koda, prepounom bagova.
Ovaj problem moemo posmatrati i sa druge strane. Pretpostavimo da imamo komplikovanu klasu koja u osnovi radi ono
to nam je potrebno, ali je potrebno da se neto malo doda. Ako promenimo izvorni kod, rizikujemo da neto poremetimo.
Zbog toga moramo da paljivo studiramo izvorni kod da bismo bili sigurni da su promene na mestu. To nije nimalo lako.
Klase predstavljaju dobru tehniku za modularnu dekompoziciju i poseduju mnoge kvalitete koji se oekuju od komponenata
za viekratnu upotrebu. One su homogeni i koherentni moduli, jasno se moe razdvojiti interfejs od implementacije itd. Ipak
da bi se postigao krajnji cilj viekratne upotrebe i proirivosti softvera potrebno je neto vie.
Da bi se izbeglo stalno prepisivanje istog koda iz poetka, gubljenje vremena, nedoslednost i rizik od pojave greaka,
potrebna je tehnika za obuhvatanje oiglednih zajednikih karakteristika, koje postoje unutar grupa sline strukture, na
primer, svih editora teksta, svih tabela itd. Istovremeno treba voditi rauna i o razlikama koje su karakteristine za pojedine
sluajeve.
Da bi se dostigli viekratna upotreba i proirivost potrebno je da iskoristimo konceptualne odnose izmeu klasa. Klasa moe
biti proirenje, specijalizacija ili kombinacija drugih klasa. Za definisanje i upotrebu tih odnosa potrebna je podrka jezika.
Tu podrku obezbeuje nasleivanje.
Nasleivanje je proces defnisanja nove klase koja nasleuje neku ve postojeu klasu. Nova klasa, koja se naziva potomak,
ili podklasa, ili subklasa, sadri sve osobine roditelja, ali ima mogunost dodavanja novih osobina.
SA GLEDITA
MODULA
Dodavanje odlika
Promena definicije
Promena imena
Skrivanje potomka
Viestruko nasleivanje
Ponovljeno nasleivanje
SA GLEDITA
TIPA
Polimorfizam
Dinamiko vezivanje
Nepotpune odlike,
operacionalizacija
Sa take gledita modula nasleivanje je posebno korisno kao tehnika za viekratnu upotrebu koda.
Modul je skup usluga koje se nude spoljanjem svetu. Bez nasleivanja svaki novi modul bi morao da samostalno definie
sve usluge koje nudi. Ne postoji, meutim, nain da se novi modul jednostavno definie dodavanjem novih usluga onima
koje ve postoje u prethodno definisanim modulima.
Nasleivanje daje tu mogunost. Ako B nasleuje A, onda sve usluge (metodi i lanovi) klase A automatski postaju
dostupni i u klasi B, bez ikakve potrebe da se u B dodatno definiu. Sa druge strane B slobodno moe dodavati nove
karakteristike za svoje potrebe. Dodatni nivo prilagodljivosti se postie ponovnim definisanjem, odnosno mogunou da B
izabere implementacije koje nudi A, pri emu neke od njih ostavlja onakvim kakve jesu, dok druge menja i prilagoava
svojim potrebama.
Ovo vodi ka stilu programiranja koji umesto da se svaki novi problem reava iz poetka, ohrabruje graenje programa na
prethodnim dostignuima i njihovim prethodnim rezultatima.
Dobar modul treba da istovremeno bude i otvoren i zatvoren. On treba da bude zatvoren poto su klijentima potrebni servisi
odreenog modula za sopstveni razvoj. Kada se odlue za neku verziju odreenog modula, uvoenje novog servisa ne bi
trebalo da utie na klijente. Sa druge strane modul treba da bude i otvoren, poto ne postoji garancija da e od poetka
obuhvatiti sve uslugekoje e klijentu potencijalno trebati.
Ovakav dvojni zahtev koji se postavlja pred module, predstavlja dilemu koju klasino programiranje ne reava. Ona se
moe reiti nasleivanjem. Klasa je zatvorena poto moe da se kompajlira, sauva u biblioteci klasa, odakle je klijentske
klase mogu koristiti. Sa druge strana klasa je i otvorena, poto je bilo koja nova klasa moe koristiti kao svog roditelja i
dodati nove karakteristike ili menjati postojee. U tom procesu nema potrebe da se menja originalna klasa ili da se smeta
njenim klijentima.
Jedan od najteih problema prilikom planiranja viekratno upotrebljivih struktura modula je neophodnost da se iskoristi
prednost zajednikih osobina koje postoje izmeu grupa povezanih apstrakcija podataka. To se upravo postie
nasleivanjem.
Ideja kod nasleivanja je da se definicija svake karakteristike podigne to vie u hijerarhiji, tako da je moe deliti to vei
broj klasa potomaka.
Ako se govori o nasleivanju sa stanovita tipa onda nasleivanje predstavlja odnos tipa je (engleski "is a"). Primer za ovo
moe biti iskaz "Svaki pas je ivotinja" i sl.
Nasleivanje se poneka posmatra kao proirenje, a ponekad kao specijalizacija. I jedno i drugo tumaenje je ispravno, iako
moda izgleda da su to kontradiktorne tvrdnje. Razlika dolazi od toga da li klasu posmatrate kao tip ili kao modul.
Ako je posmatrate kao tip, onda je oigledno u pitanju specijalizacija. Pas je mnogo ui pojam nego ivotinja.
Sa stanovita modula se klasa posmatra kao davalac usluga, odnosno B (naslednik klase A) implementira sve karakteristike
klase pretka A, ali i svoje karakteristike. Sa tog stanovita, to je proirenje.
Nasleivanje u Javi
Ako nasleivanje u programiranju posmatrate kao analogiju sa ljudskom vrstom, Java tu nije dosledna. Dete bi prirodno
nasledilo osobine oba roditelja. U Javi je dozvoljeno samo jednostruko nasleivanje. To znai da izvedena klasa moe da
ima samo jednog roditelja. Neki objektno orijentisani jezici podravaju i viestruko nasleivanje. O tome e kasnije biti vie
rei. Kreatori Jave su zakljuili da viestruko nasleivanje donosi vie tete nego koristi, pa ga zato nisu ugradili u jezik.
ematski se odnos klase roditelja i klase potomka moe predstaviti na sledei nain. Na slici su dati i termini koji se
paralelno koriste, ali u osnovi oznaavaju istu stvar.
roditelj
osnovna
klasa
super klasa
potomak
izvedena
klasa
potklasa
Izvoenje klasa se ematski obino prikazuje strelicom usmerenom od potomka prema roditelju. Vano je primetiti da se
nasleivanje odnosi na klase, a ne na objekte.
Sintaksa nasleivanja u Javi je:
class VideoKaseta{
String naslov;
// naslov filma
int
duzina;
// broj minuta
boolean raspoloziva;
// da li je kaseta na raspolaganju?
// konstruktor
public VideoKaseta ( String ttl ) {
naslov = ttl; duzina = 90; raspoloziva = true;
}
// konstruktor
public VideoKaseta ( String ttl, int lngth ) {
naslov = ttl; duzina = lngth; raspoloziva = true;
}
public void prikazi() {
System.out.println( naslov + ", " + duzina + " min. raspoloziva:" +
raspoloziva );
}
}
class VideoKlub{
public static void main ( String args[] ) {
VideoKaseta k1 = new VideoKaseta ("Matrix", 120 );
VideoKaseta k2 = new VideoKaseta ("Ratovi zvezda" );
k1.prikazi();
k2. prikazi ();
}
}
Klasa VideoKaseta je u redu za eventualno dokumentarne filmove, jer sadri osnovne informacije. ta ako bismo eleli da o
igranim filmovima imamo vie informacija, na primer rezisera i zanr. U tom sluaju bismo mogli da napravimo novu klasu
IgraniFilmovi, koja bi nasledila klasu VideoKaseta i dodala atribute koji su potrebni.
VIdeoKaseta
IgraniFilmovi
Objekat tipa IgraniFilmovi ima sledee atribute:
lan
naslov
duzina
raspoloziva
prikazi()
reziser
zanr
// predloeni konstruktor
public IgraniFilmovi( String ttl, int lngth, String dir, String rtng ){
naslov = ttl;
// ovde se radi ono to radi konstruktor
// klase roditelja.
duzina = lngth;
raspoloziva = true;
reziser = dir;
zanr = rtng;
}
Iako izgleda da ovde nije potrebno pozivati konstruktor osnovne klase, on se ipak implicitno poziva. Kompajler smatra da
prethodni kod izgleda ovako:
public IgraniFilmovi( String ttl, int lngth, String dir, String rtng ){
super(); // poziva se podrazumevani konstuktor klase roditelja
naslov = ttl;
duzina = lngth;
raspoloziva = true;
reziser = dir;
zanr = rtng;
}
Kompajler implicitno poziva podrazumevani konstruktor osnovne klase. Ako ta klasa nema podrazumevani konstruktor
moe , ali ne mora, doi do sintaktike greke.
Kada klasa ima podrazumevani konstruktor?
Ako programer nije napisao nijedan konstruktor za klasu, onda e kompajler sam napraviti podrazumevani
konstruktor.
Ako je programer napisao makar jedan konstruktor za klasu, onda se podrazumevani konstruktor ne pravi
automatski.
U primeru koji smo dali, definicija klase VideoKaseta sadri konstruktor, tako da se podrazumevani konstruktor nee
napraviti. Prema tome predloeni konstruktor iz prethodnog primera bi javio greku.
Da vidimo sada kako bismo koristili ove dve klase:
class VideoKlub{
public static void main ( String args[] ) {
VideoKaseta k1 = new VideoKaseta ("Mikrokosmos", 90 );
IgraniFilmovi k2 = new IgraniFilmovi ("Ratovi zvezda", 120,
"Lukas", "SF" );
k1.prikazi();
k2. prikazi ();
}
}
Nakon izvrenja ovog programa trebalo bi da dobijete sledei izlaz:
class VideoKlub{
public static void main ( String args[] ) {
VideoKaseta k1 = new VideoKaseta ("Mikrokosmos", 90 );
IgraniFilmovi k2 = new IgraniFilmovi ("Ratovi zvezda", 120,
"Lukas", "SF" );
k1.prikazi();
k2. prikazi ();
}
}
on e dati sledei izlaz:
Klasa Object
Nasleivanje je u Javi tako organizovano da sve klase uvek nasleuju jednu klasu, klasu Object. U pitanju je klasa koja je
unapred definisana.
ak i kada radite sa obinim klasama, kod kojih niste eksplicitno uveli nasleivanje, ono implicitno postoji. U Javi se
podrazumeva da su sve klase izvedene iz klase Object. U skladu sa ovim hijerarhija klasa za na primer bi izgledala ovako:
Object
VideoKaseta
IgraniFilmovi
U klasi Object je definisan odreen broj metoda koje nasleuju sve druge klase u Javi. To su na primer, metode toString(),
equals() i sl. Ove metode se kasnije mogu nadjaati, ali se ponekad mogu koristiti i u izvornom obliku.
Viestruko nasleivanje
Viestruko nasleivanje je u sutini samo varijacija ve pomenutog koncepta nasleivanja. Razlika je u tome to se osobine
nasleuju od vie osnovnih klasa. Razliiti autori se razliito odnose prema viestrukom nasleivanju. Neki od njih smatraju
da ono donosi vie problema nego koristi, dok drugi istiu njegov znaaj i smatraju da se pravilnom upotrebom mogu
iskoristiti samo prednosti, a da se ne zapadne u probleme. Autori Jave spadaju u prvu grupu, tako da viestruko nasleivanje
nisu ni ubacili u jezik.
OsnovnoSredstvo
Avion
AvionKompanije
U jeziku C++, koji podrava viestruko nasleivanje, to bi izgledalo ovako:
class A{
public: int i;
}
class B{
public: int i;
}
class C : public A, public B {
public: void f();
}
Druga varijanta dvosmislenosti nastaje ako postoji ponovljeno nasleivanje. U tom sluaju je re o istom imenu, ali i o
istom entitetu.
class X{
public: int i;
}
class A : public X{};
class B : public X {};
class C : public A, public B {
public: void f();
}
Kako bi se ovo reilo. Ponovo nekoliko moguih pristupa. Jedan je princip zabijanja glave u pesak. U ovoj varijanti se
zabranjuje takvo nasleivanje. Problem se vraa dizajneru osnovnih klasa i on mora da rei problem, odnosno promeni ime.
Ovo nije ni razumno ni uvek mogue. Nije razumno, zato to su dobra smislena imena retka, a viestruko nasleivanje u
puno sluajeva spaja hijerarhije koje dolaze od razliitih proizvoaa.
Druga varijanta je da se sve prebaci na onog ko pravi novu klasu. U tom sluaju programer mora da proba da sam rei sve
probleme koji nastaju usled dvosmislenosti.
Trea mogunost je da se ostavi klijentu da sam reava probleme.
U jeziku C++ se ovakvi problemi uglavnom reavaju primenom operatora za razreavanje oblasti vaenja. Pogledajmo
ponovo primer sa ponovljenim nasleivanjem:
class X{
public: int i;
}
class A : public X{};
class B : public X {};
class C : public A, public B {
public: void f();
}
Objekti klase C u ovom primeru e imati dva lana sa imenom i. U svakom objektu klase C postoje dva podobjekta tipa X.
Jedan je nasleen od A, a drugi od B. Pristup lanu i bez eksplicitnog navoenja imena klase kojoj pripada, nije dozvoljen.
Razlog je dvosmislenost. lanu i se moe pristupiti samo eksplicitnim navoenjem imena klase kojoj pripada i operatora
razreavanja oblasti vaenja.
void C::f(){
i = 0; // greska, dvosmislenost da li je i iz A ili B
A::i = B::i // ovako moze
}
Relacija izmeu prikazanih klasa se grafiki moe prikazati kao na sledeoj slici. Treba primetiti da su podobjekti tipa X,
unutar objekta tipa C, potpuno nezavisni, odvojeni objekti.
C
Posledica ovog je da nije dozvoljeno da jedna klasa bude viestruka direktna osnovna klasa, inae se ne bi mogla izbei
dvosmislenost.
Deo A
Deo B
Deo C
Redosled smetanja podobjekata osnovnih klasa nije definisan jezikom, ve zavisi od implementacije prevodioca.