Exercise index of this lecture   Alphabetic index   Course home   

Exercises and solutions
Objekt-orienteret programmering i Java, del 1


2.1   Modifikationer af Konto klassen  

Denne opgave tager udgangspunkt i programmet Babybank som vi allerede har set på ved forelæsningen.

Lav følgende ændringer i programmet:

    Tilføj en operation, som overfører et antal kroner fra een konto til en anden. Overvej omhyggeligt, hvad operationen skal hedde, og hvilke parametre den skal have Lav om på data repræsentationen i klassen Konto, således at vi nu repræsenterer kontoens tilstand som en liste (array) af transaktioner. Hvis kontoen i starten indeholder 0 kroner repræsenterer transaktionerne

      indsæt(100), hæv(50), indsæt(10)

    således en konto med 60 kroner. Det er tilladt at ændre på de private egenskaber af klassen Konto, men ingen offentlige egenskaber må ændres!

Download Babybank programmet via ovenstående link, implementer ændringerne, og få programmet til at virke. Hovedprogrammet i min udgave af programmet skal køre uændret efter ændringerne.

I har behov for at bruge Arrays (eller lignende) i denne opgave. Vi har endnu ikke set på dette emne i stor detalje, men jeg har lavet et kort demonstrationsprogram, som viser hvordan man bruger arrays. Vi vender lidt senere i kurset tilbage til arrays og lister.

Solution
Jeg har valgt at bruge native Java arrays som transaktioner. Man kunne overveje at lave en mere fleksibel løsning involverende en Collection klasse og en Transaktions klasse. I så fald skulle et objekt af typen Transkation repræsentere en enkelt transaktion på kontoten. Her er min simple løsning:

/* Denne version af programmet er løsningen på opgave A i oop-intr */

class Konto {
   private static double RenteSats = 0.02;   // altså 2% i rente
   private final static int MAXTRANSAKTIONER = 100;

   private String navn;

   private double[] transaktioner;
   private int næsteTransaktion = 0;

   Konto(String nytNavn) {
      transaktioner = new double[MAXTRANSAKTIONER];
      navn = nytNavn; 
   }

   public double balance () {
      double sum = 0.0;
      int i;
      for(i=0; i < næsteTransaktion; i++)
      sum = sum + transaktioner[i];
      return sum;
   }

   public void hæv ( double beløb ) {
     transaktioner[næsteTransaktion] = -beløb;
     næsteTransaktion = næsteTransaktion + 1;
   }

   public void indsæt ( double beløb) {
     transaktioner[næsteTransaktion] = beløb;
     næsteTransaktion = næsteTransaktion + 1;
   }         

   public void overførFra(double beløb, Konto fra) {
      fra.hæv(beløb);
      this.indsæt(beløb);
   } 

   public void tilskrivRente() {
     double rente = balance() * RenteSats;

     transaktioner[næsteTransaktion] = rente;
     næsteTransaktion = næsteTransaktion + 1;
   }

   public String toString() {
      return navn + "'s konto indeholder "
            + balance() + " kroner";
   }
} // Konto


class Bank1A {
 
   public static void main( String[] args ) {

     Konto konto1 = new Konto("Jens");
     Konto konto2 = new Konto("Peter");

     konto1.indsæt(100);
     konto2.indsæt(500);
     System.out.println(konto1);  System.out.println(konto2); System.out.println();

     konto1.indsæt(3);
     konto2.indsæt(5);
     System.out.println(konto1);  System.out.println(konto2); System.out.println();

     konto1.tilskrivRente();
     konto2.hæv(125);
     System.out.println(konto1);  System.out.println(konto2); System.out.println();

     konto1.overførFra(25, konto2);
     System.out.println(konto1);  System.out.println(konto2); System.out.println();

   }
}


Her er endvidere et link til det rene Java program .


2.2   Klassen Spillekort  

Et kortspil består af 52 kort fordelt på fire farver (betegnet hjerter, ruder, klør og spar) og 13 værdier (fra 1 til 10 samt knægt, dronning og konge).

Skriv en klasse Spillekort, som repræsenterer et enkelt kort i et kortspil. Datarepræsentation skal være privat i klassen.

Vi ønsker at bruge instanser af Spillekort i spil, hvor kortene skal sammenlignes størrelsesmæssigt med andre kort. Derfor skal der være operationer størreEnd, ligMed og mindreEnd i klassen. Sammenligningen af to kort beror udelukkende på kortets værdi; farven spiller altså ingen rolle. Vi ønsker følgende orden, hvor to er mindst og es er størst:

     2 < 3 < ... < 9 < 10 < knægt < dronning < konge < 1

Redefiner metoden toString fra Object til at returnere en tekst streng, som identificerer et spillekort entydigt i forhold til de andre spillekort, f.eks. 'klør 5' og 'spar es'.

Programmer en eller flere konstruktorer i klassen Spillekort, således at instantiering af et helt kortspil (52 kort) bliver så let som mulig (se herefter).

Skriv dernæst et program, som konstruerer et komplet spil kort bestående af 52 kort. Med andre ord, ønsker vi at programmet laver 52 objekter af klassen Spillekort. Vi ønsker ikke at skulle skrive 52 kald af new Spillekort(...) efter hinanden med forskellige parametre; det vil naturligvis være særdeles hensigtsmæssigt at kunne foretage instantieringen i en løkke. En forudsætning for at kunne gøre dette er en hensigtsmæssigt valgt Spillekort konstruktor. Organiser kortspillet i et array.

Solution
Jeg vil gerne fremhæve konstanterne for kortfarver og værdier (som ikke er numeriske). Læg også mærke til de to private operationer som hjælper toString() med at præsentere et kort på en pæn måde. I praksis ville vi nok ikke implementere ligMed, men derimod redefinere operationen equals. Min udgave af klassen Spillekort ser således ud:

public class Spillekort{

  // Farve konstanter:
  public final static int RUDER = 0;
  public final static int HJERTER = 1;  
  public final static int KLØR = 2;  
  public final static int SPAR = 3;  

  // Værdi konstanter: 
  public final static int KNÆGT = 11;  
  public final static int DRONNING = 12;  
  public final static int KONGE = 13;
  public final static int ES = 1;  

  private int farve;
  private int værdi;

  Spillekort(int farve, int værdi){
    this.farve = farve;
    this.værdi = værdi;
  }

  private String værdiPræsentation(){
    if (this.værdi == ES)            return ("Es");
    else if (this.værdi == KNÆGT)    return ("Knægt");
    else if (this.værdi == DRONNING) return ("Dronning");
    else if (this.værdi == KONGE)    return ("Konge");
    else return (Integer.toString(værdi));
  }

  private String farvePræsentation(){
    switch (this.farve) {
      case RUDER:    return("Ruder"); 
      case HJERTER:  return ("Hjerter");
      case KLØR:     return("Klør");
      case SPAR:     return("Spar");
      default: return("???");
    }
  }

  public String toString(){
    return(farvePræsentation() + " " + værdiPræsentation());
  }

  public boolean ligMed(Spillekort andetKort){
    return(this.farve == andetKort.farve && this.værdi == andetKort.værdi);
  }

  public boolean mindreEnd(Spillekort andetKort){
    int thisReelVærdi  = (this.værdi == 1) ? KONGE+1 : this.værdi;
    int andetKortReelVærdi = (andetKort.værdi == 1) ? KONGE+1 : andetKort.værdi;
    return(thisReelVærdi < andetKortReelVærdi);
  }

  public boolean størreEnd(Spillekort andetKort){
    return !(this.ligMed(andetKort) || this.mindreEnd(andetKort));
  }
}
 

Her er endvidere et link til det rene Java program .

Et helt kortspil kan repræsenteres af klassen KortSpil, som endvidere indeholder et hovedprogram der laver et spil kort:

public class KortSpil{
  
  public Spillekort[] bunke = new Spillekort[52];

  /* Lav et spil kort med 52 kort. */
  public KortSpil(){
    for(int f = Spillekort.RUDER; f <= Spillekort.SPAR; f++)
     for (int v = 1; v <= Spillekort.KONGE; v++){
       Spillekort kort = new Spillekort(f,v);
       bunke[f*13+(v-1)] = kort;
     }
  }

  /* Et hovedprogram som instantierer denne klasse og udskriver KortSpil objektets kort */
  public static void main(String[] args){
    KortSpil spil = new KortSpil();
    for (int i = 0; i < 52; i++)
      System.out.print(spil.bunke[i] + " ");
  }
}

Bemærk at vi samler kortene op i et array af størrelse 52. Bemærk også hvor omstændeligt det er at putte kortene ind i dette array (indeks beregninger). Vi vil senere i kurset møde andre array-linenede klasser, som gør dette meget lettere - og mere elegant.

Her er et link til det rene Java program af KortSpil .


2.3   Lighed mellem bankkonti  

I denne opgave arbejder vi videre på babybank som tidligere i denne lektion har været under behandling i en opgave.

Tilføj en metode equals, der angiver at to bankkonti er ens hvis følgende betingelser er opfyldt:

    Saldoerne er ens Ejerne har samme navn - dog således at navne stavet med stort og småt opfattes som værende ens ("Peter" = "peter" = "PETER")
Metoden equals er defineret i klassen Object, hvorfra alle klasser arver. Læs API dokumentationen af equals i forbindelse med løsningen af denne opgave.

Lav en klasse med en main metode, som laver to konti. Prøvekør programmet med det formål at teste om equals virker efter specifikationen.

Solution
Mit program, som løser problemet, er følgende:

class Konto {
   private double rentesats;
   private String navn;
   private double saldo;

   public Konto(String ejer) {
      rentesats = 0.02;
      navn = ejer; 
      saldo = 0;
   }

   public double balance () {
      return saldo;
   }

   public void hæv (double beløb) {
      saldo = saldo - beløb;
   }

   public void indsæt (double beløb) {
      saldo = saldo + beløb;
   }         

   public void tilskrivRente() {
      saldo = saldo + saldo * rentesats;
   }

   public boolean equals(Object other){
     if (other instanceof Konto){
       String thisLcNavn = navn.toLowerCase();
       String otherLcNavn = ((Konto)other).navn.toLowerCase();
       return
         this.saldo == ((Konto)other).saldo &&
          thisLcNavn.equals(otherLcNavn);
       }
     else return false;
   }

   public String toString() {
      return navn + "'s konto indeholder "
            + saldo + " kroner";
   }
} // End Konto



class BankEquals {
 
   public static void main( String[] args ) {

     Konto konto1 = new Konto("PETER");
     Konto konto2 = new Konto("Peter" ); 
     String str = "Mogens";

     konto1.indsæt(100);
     konto2.indsæt(101);
     System.out.println(konto1);  System.out.println(konto2);

     if (konto1.equals(konto2))
       System.out.println("Konto1 og konto2 er ens");
     else
       System.out.println("Konto1 og konto2 er forskellige");

     if (konto1.equals(str))
       System.out.println("Her er vist noget galt...");
     else
       System.out.println("En konto og en streng kan aldrig være lig med hinanden");
 
   }
}

Her er et link til programmet.Bemærk for det første, at vi vælger at lade other være at typen Object, og ikke Konto. Herved opnår vi at equals virkelig 'overrider' equals fra Object. Hvis vi valgte definitionen:

    public boolean equals(Konto other){ ... }
ville der være tale om en ny definition løsrevet fra metoden i Object.

Det skal også bemærkes at på trods af at både instansvariablene navn og saldo er private, så kan vi i equal se other's private instansvariable. Årsagen er, at det private relaterer sig til klassen - ikke de individuelle objekter. En privat egenskab i et objekt af klassen Konto kan altså ses fra alle andre Konto objekter.

Vi kunne også overveje at aflæse egenskaberne i den anden konto, other, via de offentlige metoder i klientgrænsefladen. Det har vi dog ikke gjort i vores implementation.

Bemærk også at vi returnerer false hvis other ikke er en Konto. Den generelle type af other tillader os f.eks. at afvise lighed mellem en Konto og et String objekt.


Generated: Monday March 31, 2008, 12:08:03
on the system cs-unix