Poglavje 6
Objektno programiranje

6.1 O objektnem programiranju

Primer: String je razred za delo z nizi. Z ukazoma

 

  String niz1 = new String("Prviniz"); 
  String niz2 = new String("Druginiz");

smo izdelali dva objekta razreda String in ju poimenovali z niz1 in niz2. Vsi objekti razreda String poznajo, med drugim, metodo charAt(), zato lahko, če želimo primerjati prvi črki obeh nizov, napišemo

 

  if (niz1.charAt(0) == niz2.charAt(0)) { 
    System.out.prinltn("Nizaseujematavprvicrki!"); 
  }

Bralec naj bo pri zgornji kodi pozoren na naslednje: metodo chatAt() smo klicali “na objektu” z uporabo pike – niz1.charAt() – in ne, kot bi to naredili v ne-objektnem programskem jeziku (na primer v C), kot samostojen ukaz – charAt(niz1, 0). V Javi funkcij, ki bi jih uporabljali kot samostojen ukaz, ni! Vse funkcije so vezane na objekte (ali, kot bomo videli kasneje, na razrede), zato so spremenile tudi ime – pravimo jim metode.

6.2 Karakteristike objektov

V nadaljevanju tega poglavja bomo izdelali dva razreda – razred Drevo in razred Bonsai. Kodo teh razredov bomo gradili postopoma – začeli bomo s preprostima razredoma (nalogi 6-I in 6-XII), nato ju bomo v posameznih nalogah dopolnjevali. Pri rešitvi nalog bomo navedli samo tisti del kode, ki se bo spremenil. Celotna koda razredov Drevo in Bonsai je prikazana na straneh od do .

Naloga 6-I. Napiši razred za izdelavo dreves. Drevo naj ima naslednje atribute:

Obnašanje drevesa naj bo določeno z naslednjima dvema praviloma:

 

Nekaj korakov pri reševanju naloge 6-I:

 

package objektno; 
 
public class Drevo { 
  //******************************** 
  //"stanja" drevesa (atributi) 
  int starost; 
  double visina; 
  String ime; 
 
 
  //******************************** 
  //"obnasanje" drevesa (metode) 
  void pomlad() { 
    starost = starost + 1; 
    povecajVisino(); 
  } 
 
  void povecajVisino() { 
    if (starost <= 3) 
      visina = visina + 1; 
    else 
      visina = visina + 0.2; 
  } 
 
  void izrisiSe() { 
    System.out.println(); 
    for(int i=0; i<visina; i++) 
      if (i<visina /2) 
        System.out.println("***"); 
      else 
        System.out.println("*"); 
    System.out.println(); 
  } 
}

6.3 Stanja objekta (atributi)

Naloga 6-II. Izdelaj dva objekta razreda Drevo, spremeni vrednost atributa visina pri prvem objektu in pokaži, da se vrednost atributa visina v drugem objektu NI spremenila.  

6.4 Statične spremenljivke

Glavna lastnost statične spremenljivke: vezana je na razred in ne na objekt (obstaja samo ena kopija spremenljivke in ne toliko kopij, kolikor imamo razredov). Iz tega izvirata dve posledici:

Posledica 1: Statična spremenljivka “obstaja” (t.j. jo lahko uporabim) tudi takrat, ki nimamo nobenega objekta razreda, v katerem je deklarirana.

Posledica 2: Vsi objekti tega razreda imajo ISTO vrednost statične spremenljivke. Če en od objektov spremeni vrednost statične spremenljivke, se vrednost spremeni za vse objekte.

Statične spremenljivke, ki jih včasih imenujemo tudi spremenljivke razreda, najavimo z rezervirano besedo static. V razredu Drevo deklariramo statično spremenljivko ID z

 

  static int ID;

Za sklicevanje na spremenljivko ID ne potrebujem objekta – vrednost lahko spreminjam kar na razredu. Torej, namesto NA OBJEKTU

 

  Drevo d = new Drevo(); 
  d.ID = 5;

lahko spremenljivko uporabim NA RAZREDU

 

  Drevo.ID=5;

Naloga 6-III. V razred Drevo dodaj atribut mojID, ki naj predstavlja identifikacijsko (zaporedno) številko posameznega drevesa. Vrednost atributa naj se nastavi ob izgradnji drevesa (t.j. v konstruktorju).  

Za rešitev te naloge potrebujemo statično spremenljivko, ki bo vezana na razred Drevo. Spremenljivko bomo poimenovali z ID, njeno vrednost pa bomo povečali vsakič, ko se bo izdelalo novo drevo (to je v konstruktorju). Atribut mojID (ne-statična spremenljivka, ki je vezana na posamezen objekt) pa bo ob “rojstvu” dobil vrednost ID.

V razred Drevo dodamo naslednje vrstice. Takoj po najavi razreda public static Drevo deklariramo statično spremenljivko

 

  // staticne spremenljivke 
  static int ID = 0; // stevilo do sedaj izdelanih dreves

na koncu vseh deklaracij spremenljivk pa napišemo konstruktor (podrobneje o konstuktorju preberi v poglavju 6.10).

 

  // Izgradnja drevesa -- konstruktor 
  public Drevo() { 
    // ko nastane novo drevo, se stevilo do sedaj izdelanih 
    // dreves poveca za ena ... 
    ID = ID + 1; 
 
    // ... atribut mojID pa dobi vrednost ID (zaporedna stevilka) 
    mojID = ID; 
  }

6.5 Obnašanje objekta

Obnašanje objekta narekujejo metode (angl. methods).

6.6 Parametri metode

Naloga 6-IV. V Razred Drevo dodaj metodo spremeniIme(String novoIme).  

6.7 Rezultat metode

Naloga 6-V. V razred Drevo dodaj metodo int povprecnaRast().  

6.8 Statične metode

Naloga 6-VI. V razred Drevo dodaj statično metodo za izpis navodila za obrezovanje (rezultat metode naj bo tipa void).  

V razredu Drevo dodamo metodo  

static void navodiloZaOBrezovanje() { 
  System.out.println("Drevoobrezujemo2xletno,spomladiinjeseni."); 
}

Metodo lahko potem kličemo na razredu:

 

  Drevo.navodiloZaObrezovanje();

Naloga 6-VII. Dodaj še statično metodo, ki vrne število že narejenih dreves (ID) .  

 

static int steviloIzdelanihDreves() { 
    return ID; 
}

6.9 Rezervirana beseda this

Namesto  

void spremeniIme(String novoIme) { 
      ime = novoIme; 
}

običajno pišemo

 

void spremeniIme(String ime) { 
      this.ime = ime; 
}

Priporočilo: rezervirano besedo this uporabljamo pred vsakim atributom (tudi, kadar ni nevarnosti, da bi prišlo do konflikta imen).

6.10 Konstruktor

Konstruktor je podoben metodi, vendar NI metoda. Medtem, ko je namen metode, da združuje zaporedje javanskih ukazov, je namen konstruktorja, da “ustvari” objekt. Konstruktor ima isto ime kot razred in ne vrača rezultata (niti void ne). Primer:

 

Drevo() { 
  ... // koda 
}

Konstruktor ustvari razred. Čas nastanka razreda pa je najprimernejši čas za nastavitev začetnih vrednosti atributom:

 

Drevo() { 
  // stevilo "izdelanih" dreves 
  ID = ID + 1; 
 
  mojID = ID; 
  ime = ""; 
  starost=0; 
  visina=0; 
}

Razred ima lahko več konstruktorjev; vsi imajo enako ime (ime razreda), vendar različno število in tip parametrov. Konstruktorji običajno kličejo eden drugega, v ta namen uporabijo rezervirano besedo this. Ta ima znotraj konstruktorja drug pomen kot this v metodi; v metodi pomeni ’trenutno izvedbo’ v konstruktorju pa klic drugega konstruktorja. Za vsak razred en konstruktor VEDNO obstaja (če ga ne napiše programer, ga doda prevajalnik). Privzet konstruktor je brez parametrov.

Naloga 6-VIII. V razred Drevo dodaj konstruktor z enim parametrom – imenom drevesa.  

 

  // konstruktor z enim parametrom 
  Drevo(String ime) { 
    this(); // klic konstruktorja brez parametrov 
 
    this.ime = ime; // nastavim vrednost atributa ime 
  }

.

V zvezi s konstruktorji je dobro poznati še dve pomembni dejstvi:

6.11 Skrivanje atributov

Naloga 6-IX. Ustvari primerek razreda Drevo in na njem trikrat kliči metodo pomlad() - drevo bo staro 3 leta in visoko 3. Nato “ročno” spremeni vrednost atributa starost na 10 (starost = 10) in klici metodo izrisiSe(). Kaj opaziš?  

Če pravilno rešimo prejšnjo nalogo, opazimo tole: če se starost atributa spreminja tako, kot je bilo predvideno (vsako pomlad), potem količini visina in starost ustrezata začetnim specifikacijam za drevo. Če pa nekdo ročno (hote ali nehote) spremeni vrednost enega od omenjenih atributov, pride do razhajanja med dejanskim in pričakovanim stanjem (imeli smo drevo staro 10 let, ki je bilo visoko 3 metre – toliko kot drevo staro 3 leta). Omenjenim težavam se lahko izognemo s pomočjo skrivanja atributov. Atribut, ki bi ga radi zaščitili pred “zunanjimi vplivi”, najavimo z določilom private.

Namesto

 

  int starost;

pišemo  

  private int starost;

S tem smo atribut starost skrili in do njega lahko dostopamo samo v razredu samem.

Naloga 6-X. Skrij atribut visina, nato ga poskusi na enak način kot pri prejšnji nalogi ročno popraviti.  

6.12 Getter/setter

Ko smo v prejšnji nalogi skrili atribut starost, smo preprečili, da bi ga uporabnik nekontrolirano spremnijal (natanko to smo želeli), toda s tem smo preprečili vsakršen zunanji dostop do tega atributa - uporabnik ga ne more niti brati niti spreminjati. To pa je včasih moteče (npr. če bi želeli izpisati starost drevesa, tega ne moremo storiti). Nastalo težavo rešimo z uporabo tako imenovanih getter-jev in setter-jev (t.j. metod, ki uporabniku omogočajo dostop do skritih atributov). Getter je metoda, ki omogoča branje atributa. Običajno ime: getImeAtributa (primer: getStarost()). Setter je, nasprotno, metoda, s katero lahko kontrolirano nastavim vrednost atributa. Običajno ime: setImeAtributa (primer: setStarost()).

Naloga 6-XI. Napiši getter in setter za starost  

Koda getterja in setterja je običajno zelo preprosta. Getter vrne vrednost atributa, setter pa to vrednost nastavi (in opravi še morebitna dodatna opravila). V našem primeru bo getter preprosto

 

  public int getStarost() { 
    return starost; 
  }

v setterju pa moramo poleg starosti primerno popraviti še visino (ta je odvisna od starosti).

 

  public void setStarost(int starost) { 
    this.starost = starost; // nastavimo starost ... 
 
    // ... in starosti prilagodimo se visino 
    if (starost < 4) 
      visina = starost; 
    else 
      visina = 3 + (starost - 3) * 0.2; 
  }

6.13 Rezervirana beseda instanceof

Če imamo objekt x in bi radi preverili, ali je x objekt razreda X, uporabimo rezervirano besedo instanceof

 

  x instanceof X    //    (rezultat: true ali false)

Primer:  

  Drevo d1 = new Drevo(); 
  boolean jeDrevo = d1 instanceof Drevo; 
  System.out.println(jeDrevo);            // izpise true 
 
  String s = "Test"; 
  System.out.println(s instanceof Drevo)  // izpise false 
  System.out.println(s instanceof String) // izpise true

6.14 Razširitve razredov in dedovanje

Razširitve razredov in dedovanje spadata med najpomembnejše koncepte objektnega programiranja. Osnovna ideja dedovanja:

 
Za razširitev razreda uporabim rezervirano besedo extends. Primer: z deklaracijo

 

class Bonsai extends Drevo { 
 
}

ustvarim razred Bonsai, ki se ujema z razredom Drevo v vseh metodah in atributih. Če želim, lahko (znotraj oklepajev {}) nekatere metode razreda Bonsai napišem na novo (redefiniram), napišem pa lahko tudi nove metode (take, ki v razredu Drevo ne obstajajo). Metode, ki jih v novem razredu ne redefiniram, ostanejo enake kot v njegovem predniku (so od njega podedovane).

Izrazi: prvotni razred je prednik (oče, nadrazred, (angl. super class)), razširjeni razred pa potomec (sin, podrazred, (angl. sub class)). Primer: razred Bonsai je potomec razreda Drevo, razred Drevo je prednik razreda Bonsai.

Naloga 6-XII. Napiši razred Bonsai, kot potomca razreda Drevo. V njem popravi (redefiniraj) metodo povecajStarost (bonsai raste po 5 cm prvi 2 leti, potem pa se rast v višino ustavi), popravi tudi metodo izrisiSe().  

 

public class Bonsai extends Drevo{ 
   // vse atribute in metode podedujemo od razreda Drevo ... 
 
  //... spremenimo le metodo za povecevanje visine (bonsai raste 
  // mnogo pocasneje kot drevo) ... 
  void povecajVisino() { 
   if (getStarost() < 3) 
     setVisina(getVisina() + 0.05); 
  } 
 
  // ... ter metodo za izris na zaslon (bonsai izgleda kot pikica) 
  void izrisiSe() { 
    System.out.println("JazsemBONSAIIII"); 
    System.out.println("."); 
  } 
}

6.15 Nove metode in atributi ter rezervirana beseda super

Naloga 6-XIII. V razred Bonsai dodaj atribut sirina (koliko je bonsai širok v cm); vsako pomlad naj se sirina poveča za 2 cm. Širino lahko zmanjšamo, če bonsai ostrižemo (vsako striženje: -1cm). Dodaj še metodo za striženje.  

Nalogo rešimo tako, da v razred Bonsai najprej dodamo atribut sirina.

 

  // sirina bonsaia (v centimetrih) 
  int sirina;

Njegova vrednost se spremeni vsako pomlad - poveča se za dva. Popraviti moramo torej metodo pomlad(): poleg običajnih stvari, ki se dogajajo z drevesom (poveča se starost in drevo zraste), v metodi pomlad povečamo še širino. Kako pa opravimo “običajne stvari”, ki se zgodijo z drevesom spomladi? S klicem metode pomlad() nadrazreda Drevo – to storimo z ukazom super.pomlad().

 

  void pomlad() { 
    // vsako pomlad se z bonsajem zgodi isto, kot 
    // z vsakim drevesom ... 
    super.pomlad(); 
 
    //... poleg tega pa zraste se malo v sirino 
    sirina += 2;

V razred Bonsai dodamo še metodo za striženje.

 

  void strizanje() { 
    if (sirina > 1) 
      sirina--; 
  }

6.16 Katerega tipa (razreda) je nek objekt?

Naredimo objekt razreda Drevo:

 

  Drevo d = new Drevo();

Ker je d primerek razreda Drevo, bo ukaz

 

  System.out.println(d instanceof Drevo);

izpisal true. Podobno: naredimo objekt razreda Bonsai:

 

  Bonsai b = new Bonsai();

Ker je b primerek razreda Bonsai, bo ukaz

 

  System.out.println(b instanceof Bonsai);

izpisal true. Toda pozor: b je tudi primerek razreda Drevo, saj je Bonsai naslednik razreda Drevo (b ima vse kot Drevo, morda celo kaj več). Ukaz

 

  System.out.println(b instanceof Drevo);

bo izpisal true, ukaz

 

  System.out.println(d instanceof Bonsai);

pa seveda false. Ker je Bonsai nadgradnja razreda Drevo, lahko napišemo tudi tole:

 

  Drevo db = new Bonsai();

vendar potem lahko na objektu db kličemo le metode, ki jih pozna Drevo, ne pa tudi tistih, ki jih je uvedel Bonsai. Metode razreda Bonsai lahko na objektu db izvajamo le tako, da prevajalniku povemo, kakšnega tipa db dejansko je.

 

  ((Bonsai) db).strizenje();

Z (Bonsai) db smo prevajalniku povedali, da je db tipa Bonsai, nato smo na njem klicali metodo strizenje(). Seveda pa bi prišlo do napake, če bi za objekt, ki dejansko ne bi bil razreda Bonsai trdili, da je!

 

  Drevo db = new Bonsai(); 
  db.izrisiSe(); 
  db.strizenje(); 
  // Error: cannot find symbol - method strizenje() 
  ((Bonsai) db).strizenje(); 
  // OK, klice se metoda strizenje() 
 
  Drevo d = new Drevo(); 
  ((Bonsai) d).strizenje(); 
  //  Error: java.lang.ClassCastException

6.17 Pra-oče Object

Naloga 6-XIV. Ustvari objekt razreda Drevo in ga izpiši. Nato popravi metodo toString() in ga ponovno izpiši.  

Rešitev naloge 6-XIV, skupaj s celotno kodo razreda Drevo je prikazana v spodnji kodi. Spodaj je prikazana tudi koda razreda Bonsai.

Razred Drevo objektno/Drevo.java

 

Razred Bonsai objektno/Bonsai.java

 

6.18 Abstraktne metode in razredi

Pomen in način uporabe abstraktnih razredov bomo prikazali na naslednjem primeru. Izdelali bomo program za računanje ničle funkcije, pri tem pa bomo uporabili Newtnovo interpolacijsko metodo. Ta predvideva, da ničlo funkcije iščemo v več korakih. Začnemo v neki točki x0, ki naj bo čim bližje prave ničle. Točki x0 rečemo “začetni približek”. V vsakem koraku iz trenutnega približka za ničlo izračunamo naslednji približek po formuli

           f(x0)
x1 = x0 - --′---,
          f (x0)

kjer f(x0) predstavlja vrednost funkcije f v točki x0, f(x0) pa vrednost odvoda funkcije f v tej točki. Psevdokoda za računanje ničle funkcije f(x) z uporabo Newtnove interpolacijske formule je sledeča (x0 je začetni približek, N pa število korakov):

izracunajNiclo(x0, N):  
  stevilo_korakov = 0;  
  dokler (stevilo_korakov < N) {  
    stevilo_korakov++;  
    x1 = x0 - f(x0) / f’(x0);  
    x0 = x1;  
 
  return x0;

Naloga 6-XV. Napiši program za računanje ničle funkcije - uporabi Newtnovo interpolacijsko metodo. Kot osnovo uporabi abstraktni razred Funkcija.  

Za rešitev te naloge potrebujemo abstraktni razred Funkcija, ki bo predstavljal poljubno funkcijo. Za potrebe Newtnove metode mora Funkcija poznati naslednje metode: vrednost(double x), ki vrne vrednost v točki x in odvod(double x), ki vrne vrednost odvoda funkcije v točki x. Začetna koda razreda Funkcija se torej glasi:

 

public abstract class Funkcija { 
    abstract double vrednost(double x); 
    abstract double odvod(double x); 
}

Metoda za računanje ničle je direkten prepis psevdokode, ki smo jo navedli zgoraj. Ker je metoda za računanje ničla splošna metoda, ki je enaka za vse funkcije, jo lahko napišemo kar v razred Funkcija.

Razred Funkcija objektno/afunkcije/Funkcija.java

 

Kako pa lahko razred Funkcija uporabimo? Ker je to abstraktni razred, ga takega kot je ne moremo uporabiti za računanje ničel konkretnih funkcij. Preden ga uporabimo moramo abstraktne metode dejansko napisati. To starimo v razredu potomcu, ki od očeta podeduje vse ne-abstraktne metode (v našem primeru metodo izracunajNiclo), abstraktne metode pa poda sam. Poglejmo na primeru. Recimo, da bi želeli računati ničlo funkcije sin(x). Izdelali bomo naslednika razreda Funkcija in v njem povedali, kaj metodi vrednost() in odvod() za konkretno funkcijo pomenita. Spomnimo se, da je odvod funkcije sin(x) enak cos(x) in napišimo:

Primer implementacije funkcija sin(x) objektno/afunkcije/Sinus.java

 

Pravilnost delovanja preiskusimo z naslednjim primerom.

Preiskus delovanja Newtnove metode za računanje ničle objektno/afunkcije/Test.java

 

Izkaže se, da metoda deluje presenetljivo dobro – pri začetnem približku 2 smo ničlo (π) že v šestih korakih izračunali na 15 decimalk natančno.

6.19 Vmesnik

Vmesnik in abstraktni razred sta dva sorodna koncepta – uporabljamo ju v podobne namene, vsak pa imata svoje prednosti in slabosti. V nadaljevanju bomo nalogo za računanje ničle funkcije rešili z uporabo vmesnika, bralec pa naj bo pozoren na razlike med to in prejšnjo rešitvijo. (Opomba: koda za rešitev naloge s pomočjo vmesnika se nahaja v paketu vfunkcije, koda rešitve z abstraktnim razredom pa v paketu afunkcije).

Glavna omejitev, pri delu z vmesnikom je, da ta ne more vsebovati konkretnih implementacij metod (abstraktni razred pa lahko). V čem pa je prednost vmesnika pred abstraktnim razredom? Zaradi osnovne zasnove Java ne podpira večkratnega dedovanja (razred torej ne more podedovati od več očetov), podpira pa večkratno implementacijo vmesnikov. Koda

 

class A extends razredA, razredB {  // to ne gre! 
  .. 
}

torej NI veljavna (prevajalnik tega ne bo prevedel), koda

 

class A implements vmesnikA, vmesnikB { // to je OK 
  ... 
}

pa je veljavna in hkrati v praksi pogosto uporabljena možnost.

6.20 Še en primer objektnega programiranja

Koncept objektnega programiranja bomo skušali predstaviti še na primeru iz realnega življenja. Ogledali si bomo poenostavljen in delno prilagojen problem hradnje verige hotelov.

Investitor se je odločil zgraditi verigo hotelov. Za dovoljenje je najprej vprašal na upravni enoti, kjer so izdali dokument “Osnovne zahteve za gradnjo hotelov”, ki se glasi takole:

Osnovne zahteve za gradnjo hotelov

Investitor, ki želi pridobiti dovoljenje za gradnjo hotelov, mora pripraviti projektno dokumentacijo, sestavljeno iz naslednjih delov.

Gradbeni načrt,
ki vsebuje natančna navodila za izgradnjo dveh tipov hotelov - hotel z in hotel brez kleti.
Načrt dela z obiskovalci,
ki vsebuje opis postopkov za
  • registracijo obiskovalcev ter
  • odjavo obiskovalcev.
Računovodski načrt,
ki vsebuje postopek za
  • računanje dnevnega prometa.

 

Investitor je najel projektante, ki so pripravili projektno dokumentacijo, skladno z opisanim dokumentom. Pripravili so gradbeni načrt z natančnim opisom poteka gradnje. V načrtu dela z obiskovalci so predvideli knjigo gostov, v katero se bodo ti vpisovali (za vsako sobo hotela je predvidena ena stran v knjigi) ter opisali postopek registracije (gost se vpiše v knjigo) in odjave (gost se v knjigi prečrta). Postopek za računanje dnevnega prometa so opisali takole: dnevni promet je enak ceni ene nočitve (ta je napisana na posebej za to določenem mestu v recepciji) pomnoženi s številom gostov v hotelu. Ker so projektanti ocenili, da bo v hotelu veliko tujih gostov, so v računovodski načrt dodali še opis postopka za pretvorbo valute iz EUR v SIT.

Ko je investitor prejel projektno dokumentacijo, jo je odnesel na upravno enoto, kjer so pregledali, ali je ta skladna z “Osnovnimi zahtevami za gradnjo hotelov” in z ostalimi “splošno znanimi” pravili. Šele, ko občina projektno dokumentacijo v celoti potrdi lahko investitor začne z delom.

Dokler investitor hotelov ne začne graditi, si s potrjeno dokumentacijo na more prav veliko pomagati. Lahko uporabi le tiste komponente dokumentacije, ki niso vezane na konkretno izvedbo projekta. Ne more, na primer, registrirati obiskovalca, saj ga nima kam namestiti, lahko pa, na primer, pove, koliko bo stala ena nočitev. Poleg tega lahko uporabi računovodski del projektne dokumentacije, ki opisuje način pretvorbe med valutami - ta ni odvisen od dejanske postavitve hotelov.

Ko ima investitor potrjeno dokumentacijo, začne z gradnjo prvega hotela - šele takrat projekt v nekem smislu zares zaživi. Po isti dokumentaciji lahko izdela več hotelov - vsi bodo enaki na pogled in v vseh bodo veljala enaka pravila za delo z obiskovalci in enaka računovodska pravila.

Čez čas se investitor odloči, da bo začel graditi še hotele z zunanjim bazenom. Projektantom naroči, naj izdelajo projektno dokumentacijo. Ti vzamejo dokumentacijo in v gradbeni del (navodila za postavitev hotela) napišejo: postavi hotel po prejšnjem načrtu, nato na vrt postavi hotel znanega dobavitelja. Ko občina potrdi tudi to dokumentacijo lahko investitor gradi hotele brez ali hotele z bazenom (oboji pa so lahko brez ali s kletjo).

6.20.1 Vzporednice z objektnim programiranjem

Vmesnik = Dokument “Osnovne zahteve za gradnjo hotelov”

V dokumentu so predpisane osnovne zahteve (minimalna vsebina) končnega izdelka. Ni predpisano, kako naj se kakšna stvar naredi, predpisano je, kaj naj se naredi.

Projektna dokumentacija je vsebovala VEČ, kot je bilo predpisano v dokumentu - vmesnik predpiše minimum, lahko naredimo več.

Programerji == Projektanti

Tako kot so imeli projektanti proste roke, da izvedejo projekt, imajo pogosto tudi programerji; treba se je le držati osnovnih zahtev (vmesnik) in ostalih šplošno znanih”pravil (sintaksa programskega jezika).

Razred (.java) = Projektna dokumentacija

Konstruktor == Navodila za izgradnjo hotela

Gradbeni del projektne dokumentacije v katerem je opisano, kako se hotel zgradi (postavi). Uporabi se samo v fazi izgradnje hotela, ko hotel enkrat stoji, navodil ne potrebujemo več.

Več različic navodil za izgradnjo (hotel s kletjo in hotel brez kleti) predstavlja več različnih konstruktorjev.

Atributi == podatki

Metode == postopki

Prevajalnik == upravna enota

Upravna enota preveri, ali je dokumentacija skladna z izdanim dokumentom in ostalimi pravili.

Preveden razred (.class) == potrjena projektna dokumentacija

Hotele lahko gradimo šele, ko imamo potrjeno projektno dokumentacijo.

Objekt

Postavljen hotel; šle ko postavimo hotel, stvar v resnici zaživi.

Izpeljan razred == projektna dokumentacija za hotel z bazenom

Implementacija hotelov po zgornjih specifikacijah:

Vmesnik Osnovne zahteve objektno/hotel/OsnovneZahteve.java

 

 
Razred Hotel (implementira zgornji vmesnik) objektno/hotel/Hotel.java

 

 
Razred Graditelj - test pravilnosti delovanja vseh vmesnikov in razredov objektno/hotel/Graditelj.java

 

 
Razšititev osnovnega hotela objektno/hotel/HotelZBazenom.java