Løsningsforslag Videregående programmering, eksamen desember 2010 Oppgave 1a public Prosjekt(int prosjnr, String prosjnavn, ArrayList<PersonTime> persontimer) { this.prosjnr = prosjnr; this.prosjnavn = prosjnavn; for (PersonTime p : persontimer) { this.persontimer.add(new PersonTime(p)); // dyp kopiering for å beskytte PersonTime-objektene Utvidelse, klassen PersonTime: public PersonTime(PersonTime original) { // kopikonstruktør, oppgave 1a (side 403-404) this(original.pers); anttimer = original.anttimer; Oppgave 1b public String tostring() { java.util.formatter f = new java.util.formatter(); String res = "Prosjekt: " + prosjnr + " " + prosjnavn + " med deltakere:\n"; f.format("%s", res); for (PersonTime pt : persontimer) { f.format("%s, antall timer: %.1f\n", pt.getperson().tostring(), pt.getanttimer()); return f.tostring(); Oppgave 1c public boolean equals(object detandre) { // Like hvis prosjnr og/eller navn likt. if (!(detandre instanceof Prosjekt)) { return false; if (this == detandre) { return true; Prosjekt p = (Prosjekt) detandre; return (prosjnr == p.prosjnr prosjnavn.equalsignorecase(p.prosjnavn)); 1
Oppgave 1d public double finntimekostnader(double faktor) { double sum = 0.0; for (PersonTime pt : persontimer) { sum += pt.getperson().gettimelønn() * pt.getanttimer(); return sum * faktor; Oppgave 2a public Person[] hentpersoner() { Person[] ptabell = new Person[personer.size()]; for (int i = 0; i < ptabell.length; i++) { ptabell[i] = personer.get(i); return ptabell; Svar på spørsmålet: Vi trenger ikke bruke dyp kopiering her. Grunnen er at Person er en immutabel klasse. Oppgave 2b public boolean registrernyttprosjekt(prosjekt nyttprosjekt) { if (prosjekter.indexof(nyttprosjekt) >= 0) { // her blir equals()-metoden fra oppg 1c brukt return false; else { prosjekter.add(nyttprosjekt); return true; Oppgave 2c public double finntotaletimekostnader(double faktor) { double total = 0.0; for (Prosjekt p : prosjekter) { total += p.finntimekostnader(faktor); return total; Oppgave 3 GUI-konstruktøren ser i sin helhet slik ut: public GUI(Register reg) { this.reg = reg; setdefaultcloseoperation(jframe.exit_on_close); 2
settitle("registrer nytt prosjekt"); setlayout(new BorderLayout()); add(new FeltInput(), BorderLayout.NORTH); liste = new JList(reg.hentPersoner()); JScrollPane personliste = new JScrollPane(liste); JViewport jvp = new JViewport(); jvp.setview(new JLabel("Velg personer fra listen.")); personliste.setcolumnheader(jvp); liste.setselectionmode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); // (dette er defaultverdien) add(personliste, BorderLayout.CENTER); knapp.addactionlistener(new Knappelytter()); add(knapp, BorderLayout.SOUTH); pack(); Metoden actionperformed() ser slik ut: public void actionperformed(actionevent hendelse) { int pid = 0; try { pid = Integer.parseInt(idFelt.getText()); catch (NumberFormatException e) { showmessagedialog(null, "Du skrev inn " + idfelt.gettext() + " som prosjektnr. Du må skrive inn et heltall."); return; String navn = navnefelt.gettext().trim(); if (navn.equals("")) { showmessagedialog(null, "Navnefeltet må fylles ut."); return; ArrayList<PersonTime> personliste = opprettpersontimeliste(); Prosjekt nyttprosjekt = new Prosjekt(pId, navn, personliste); if (reg.registrernyttprosjekt(nyttprosjekt)) { showmessagedialog(null, "Prosjekt registrert."); System.out.println("Prosjekt registrert: " + nyttprosjekt.tostring()); else { showmessagedialog(null, "Prosjekt med dette nr og/eller navn er registrert fra før."); 3
private ArrayList<PersonTime> opprettpersontimeliste() { Object[] valgtepersoner = liste.getselectedvalues(); ArrayList<PersonTime> personliste = new ArrayList<PersonTime>(); for (int i = 0; i < valgtepersoner.length; i++) { Person valgt = (Person) valgtepersoner[i]; personliste.add(new PersonTime(valgt)); return personliste; Oppgave 4 Vi løse oppgaven ved å definere en standardutgave av metoden finntimekostnader() i klassen Prosjekt (alternativt kan en lage denne metoden abstrakt, eventuelt kan en la finnfaktor() være polymorf i stedet for finntimekostnader()) : double sum = 0.0; for (PersonTime pt : persontimer) { sum += pt.getperson().gettimelønn() * pt.getanttimer(); return sum; Så følger de tre subklassene: class InternProsjekt extends Prosjekt { public static final double FAKTOR_INTERN_PROSJEKT = 1.4; public InternProsjekt(int prosjnr, String prosjnavn, ArrayList<PersonTime> persontimer) { super(prosjnr, prosjnavn, persontimer); return super.finntimekostnader() * FAKTOR_INTERN_PROSJEKT; class OffentligProsjekt extends Prosjekt { // Beslutningstabell for å bestemme timekostnader, se metoden finnkostnadprtime () public static final int[] GRENSER = {3, 5; public static final double[] TIMEKOSTNAD = {500.0, 600.0, 700.0; 4
public OffentligProsjekt(int prosjnr, String prosjnavn, ArrayList<PersonTime> persontimer) { super(prosjnr, prosjnavn, persontimer); double sum = 0.0; for (PersonTime pt : getpersontimer()) { sum += pt.getanttimer() * finnkostnadprtime(pt.getperson().finnkategori()); return sum; public static double finnkostnadprtime(int kategori) { for (int i = 0; i < GRENSER.length; i++) { if (kategori < GRENSER[i]) { return TIMEKOSTNAD[i]; return TIMEKOSTNAD[GRENSER.length]; class OrdinærtProsjekt extends Prosjekt { private final double faktor; public OrdinærtProsjekt(int prosjnr, String prosjnavn, ArrayList<PersonTime>persontimer, double faktor) { super(prosjnr, prosjnavn, persontimer); this.faktor = faktor; return super.finntimekostnader() * faktor; Endringer i klassen Prosjekt: Se begynnelsen av oppgaven. Endringer i klassen Register: Ingen faktor i løsningen til oppgave 1c: public double finntotaletimekostnader() { double total = 0.0; for (Prosjekt p : prosjekter) { total += p.finntimekostnader(); return total; 5
Revidert GUI: FeltInput (som før) ProsjektTypeValg Prosjektdata Nye objektvariabler i klassen GUI: private JRadioButton ordinærtprosjekt = new JRadioButton("Ordinært prosjekt", true); private JRadioButton internprosjekt = new JRadioButton("Internt prosjekt", false); private JRadioButton offentligprosjekt = new JRadioButton("Offentlig prosjekt", false); To nye paneler (se figuren): public class ProsjektTypeValg extends JPanel { public ProsjektTypeValg() { setlayout(new FlowLayout()); ButtonGroup typeprosjektgruppe = new ButtonGroup(); typeprosjektgruppe.add(ordinærtprosjekt); typeprosjektgruppe.add(internprosjekt); typeprosjektgruppe.add(offentligprosjekt); add(ordinærtprosjekt); add(internprosjekt); add(offentligprosjekt); public class Prosjektdata extends JPanel { public Prosjektdata() { setlayout(new BorderLayout()); add(new FeltInput(), BorderLayout.NORTH); add(new ProsjektTypeValg(), BorderLayout.SOUTH); Det er Prosjektdata som nå brukes i GUI-konstruktøren: add(new Prosjektdata(), BorderLayout.NORTH); I actionperformed() må vi ta hensyn til hvilken type prosjektobjekt som skal lages: 6
Før: Prosjekt nyttprosjekt = new Prosjekt(pId, navn, personliste); Nå: Prosjekt nyttprosjekt = opprettprosjektobjekt(pid, navn, personliste); Her bruker vi en metode som oppretter prosjekt av riktig type: private Prosjekt opprettprosjektobjekt(int pid, String navn, ArrayList<PersonTime> personliste) { if (ordinærtprosjekt.isselected()) { double faktor = // bruker metode fra side 496 i boka mittbibliotek.dataleser.lesdesimaltall("ordinært prosjekt er valgt. " + "\noppgi faktor for påslag ved beregning av prosjektkostnader: "); return new OrdinærtProsjekt(pId, navn, personliste, faktor); else if (internprosjekt.isselected()) { return new InternProsjekt(pId, navn, personliste); else if (offentligprosjekt.isselected()) { return new OffentligProsjekt(pId, navn, personliste); return null; // skal ikke kunne komme hit, pga at en av radioknappene alltid må være valgt 7