← Tilbake

Lag et utlånssystem i Java

Du skal lage et lite bibliotek i Java. Biblioteket har både bøker og filmer. De har ulike egenskaper, men begge kan lånes ut.

Sentrale konsepter

Klasse

Oppskriften

En klasse beskriver hvilke data og metoder en type ting skal ha.

Objekt

Den faktiske tingen

Et objekt er én konkret bok eller film som er laget fra en klasse.

Arv

Felles kode

Bok og Film kan arve felles utlånslogikk fra samme klasse.

Mål for oppgaven

  • Forklare forskjellen på klasse og objekt.
  • Lage flere Java-klasser i samme IntelliJ-prosjekt.
  • Bruke konstruktør, felter og metoder.
  • Se hvorfor objektorientering gjør koden ryddigere når flere ting ligner på hverandre.

Før du starter

Bruk samme prosjekt. Du kan fint bruke samme IntelliJ-prosjekt som i forrige oppgave, eller lage et nytt prosjekt hvis læreren ber om det.
Hvorfor Utlan? Vi kaller klassen Utlan uten å, fordi Java-klassenavn bør skrives uten æ, ø og å.
Én klasse per fil. Hver public class skal ligge i sin egen fil: Utlan.java, Bok.java, Film.java og Main.java.

Del 1 - Klasse og objekt

Tenk på en klasse som en oppskrift. Klassen sier hvilke egenskaper og handlinger en ting skal ha.

Et objekt er en konkret ting laget fra oppskriften.

Klasse: Bok
Beskriver at bøker har tittel, forfatter og antall sider.
Objekt: harryPotter
En bestemt bok med egne verdier.
Kort sagt: Klassen er typen. Objektet er én faktisk utgave av typen.

Del 2 - Lag klassen Utlån

Først lager vi en felles klasse for alt som kan lånes ut. Bøker og filmer har begge tittel og statusen erLantUt.

  1. 2.1Høyreklikk på src i IntelliJ.
  2. 2.2Velg New -> Java Class.
  3. 2.3Kall klassen Utlan.
public class Utlan {
    protected String tittel;
    protected boolean erLantUt;

    public Utlan(String tittel) {
        this.tittel = tittel;
        this.erLantUt = false;
    }

    public void lanUt() {
        if (erLantUt) {
            System.out.println(tittel + " er allerede lånt ut.");
        } else {
            erLantUt = true;
            System.out.println(tittel + " er nå lånt ut.");
        }
    }

    public void leverInn() {
        erLantUt = false;
        System.out.println(tittel + " er levert inn.");
    }

    public void skrivInfo() {
        String status = erLantUt ? "Utlånt" : "Ledig";
        System.out.println(tittel + " - " + status);
    }
}
Hva betyr this.? this betyr "dette objektet". Når vi skriver this.tittel = tittel;, sier vi: feltet tittel i dette objektet skal få verdien som kom inn i konstruktøren.
Hvorfor protected? Det betyr at underklasser som Bok og Film får bruke feltet direkte. Senere kan dere lære en mer kontrollert variant med private og getters.

Del 3 - Lag Bok og Film

Nå lager vi to mer spesifikke klasser. Begge arver fra Utlan. Det betyr at de får lanUt(), leverInn() og tittel gratis.

Lag Bok.java

public class Bok extends Utlan {
    private String forfatter;
    private int antallSider;

    public Bok(String tittel, String forfatter, int antallSider) {
        super(tittel);
        this.forfatter = forfatter;
        this.antallSider = antallSider;
    }

    @Override
    public void skrivInfo() {
        String status = erLantUt ? "Utlånt" : "Ledig";
        System.out.println("Bok: " + tittel);
        System.out.println("Forfatter: " + forfatter);
        System.out.println("Sider: " + antallSider);
        System.out.println("Status: " + status);
        System.out.println();
    }
}
Hva betyr extends? public class Bok extends Utlan betyr at Bok bygger videre på Utlan. En bok er altså en type utlån, og får derfor metodene lanUt() og leverInn() fra Utlan.
Hva betyr super(tittel)? super sender tittelen videre til konstruktøren i klassen vi arver fra. Her får Utlan ansvar for å lagre tittel og starte med erLantUt = false.
Hva betyr @Override? Det betyr at Bok lager sin egen versjon av en metode som allerede finnes i Utlan. Begge har skrivInfo(), men bok-versjonen skriver også ut forfatter og antall sider.

Lag Film.java

public class Film extends Utlan {
    private String regissor;
    private int spilletidMinutter;

    public Film(String tittel, String regissor, int spilletidMinutter) {
        super(tittel);
        this.regissor = regissor;
        this.spilletidMinutter = spilletidMinutter;
    }

    @Override
    public void skrivInfo() {
        String status = erLantUt ? "Utlånt" : "Ledig";
        System.out.println("Film: " + tittel);
        System.out.println("Regissør: " + regissor);
        System.out.println("Spilletid: " + spilletidMinutter + " min");
        System.out.println("Status: " + status);
        System.out.println();
    }
}
Samme mønster her: Film bruker også extends, super(...), this. og @Override. Forskjellen er at filmen har egne felt: regissor og spilletidMinutter.
Legg merke til: Bok og Film har ulike egenskaper, men samme utlånsfunksjon. Det er en viktig fordel med objektorientert programmering.

Del 4 - Lag objekter i Main

Å lage et objekt betyr at vi bruker new. Her lager vi to bok-objekter og ett film-objekt.

Åpne Main.java og bruk denne koden:

public class Main {
    public static void main(String[] args) {
        Bok bok1 = new Bok("Hobbiten", "J.R.R. Tolkien", 310);
        Bok bok2 = new Bok("Kodeknekkerne", "Ada Lovelace", 180);
        Film film1 = new Film("Wall-E", "Andrew Stanton", 98);

        bok1.skrivInfo();
        bok2.skrivInfo();
        film1.skrivInfo();
    }
}
Forklaring: Bok er klassen. bok1 og bok2 er to ulike objekter laget fra samme klasse.

Del 5 - Test utlån

Nå tester vi at samme metode fungerer på både bøker og filmer.

Legg dette nederst i main-metoden:

System.out.println("--- Låner ut ---");
bok1.lanUt();
film1.lanUt();

System.out.println();
System.out.println("--- Status etter utlån ---");
bok1.skrivInfo();
film1.skrivInfo();

System.out.println("--- Prøver å låne samme bok igjen ---");
bok1.lanUt();

System.out.println();
System.out.println("--- Leverer inn ---");
bok1.leverInn();
bok1.skrivInfo();
Hva viser dette? Du slipper å skrive egen utlånskode for bok og egen utlånskode for film. Felles kode ligger i Utlan.

Del 5b - Gjør testen tydeligere

I forrige del testet du manuelt ved å lese utskriften fra skrivInfo(). Nå gjør vi testen litt tydeligere: Vi skriver hva vi forventer, og lar programmet skrive true hvis det stemmer.

For at dette skal virke, trenger Utlan-klassen en getter som forteller om objektet er utlånt:

public boolean erUtlant() {
    return utlant;
}

Legg deretter disse enkle testene nederst i main:

System.out.println("--- Tester utlån ---");

Bok testBok = new Bok("Testbok", "Testforfatter", 100);
System.out.println("Ny bok er ikke utlånt: " + (testBok.erUtlant() == false));

testBok.lanUt();
System.out.println("Etter lanUt er boka utlånt: " + (testBok.erUtlant() == true));

testBok.leverInn();
System.out.println("Etter leverInn er boka ledig: " + (testBok.erUtlant() == false));
Hva er testen? Hver linje sammenligner faktisk status med forventet status. Hvis du får true, stemmer forventningen. Hvis du får false, har du funnet noe du må undersøke.

Del 6 - Videreutvikling

Velg én eller flere små forbedringer:

  • Lag klassen Spill som også arver fra Utlan.
  • Legg til aldersgrenseFilm.
  • Legg til sjangerBok.
  • Lag metoden erTilgjengelig() som returnerer true eller false.
  • Lag en enkel liste med flere utlån: Utlan[] bibliotek = { bok1, bok2, film1 };
Ekstra utfordring: Bruk en for-løkke til å skrive ut alle objektene i biblioteket. Da ser du at Java kan behandle bøker og filmer som samme hovedtype: Utlan.

Refleksjon

  • Hva er forskjellen på klassen Bok og objektet bok1?
  • Hvorfor er det smart at Bok og Film arver fra Utlan?
  • Hva måtte du endret hvis biblioteket også skulle ha spill, tegneserier eller lydbøker?