Fokus i del 3 er organisering av objektorientert kode med arv. Oppgaven kan derfor løses ved hjelp av pseudokode.
Systemet skal støtte tre ulike logikker for å knytte doktor til pasient: - Pasienter knyttes til den første (men ikke nødvendigvis beste) doktoren som kan behandle en eller flere tilstander hos pasienten. (TreatmentUnit)
- Pasientene kan ha tilstander med varierende kritikalitet, som gjør at de prioriteres foran resten av køen når en doktor er ledig. Gjør nødvendige antakelser om en getPriority-metode som brukes til prioritering. Per, som har en mer alvorlig skade enn Jens, vil altså behandles raskere selv om han kommer inn senere. (Såfremt ikke Jens allerede har startet behandling.) (PriorityTreatmentUnit)
- Pågående pasientbehandling (selv om den er prioritert som over) skal kunne avbrytes og doktoren skal starte behandling av en ny pasient. Dette skal skje dersom det kommer inn en ny pasient, og dennes prioritet er høyere enn hos den som er til behandling. Du kan også her forutsette at det finnes en getPriority-metode i Patient. Anta at Jens er under behandling hos doktor Who. Ida kommer til behandling, har en tilstand med høyere prioritet enn Jens, og kan kun behandles av Who. Jens sin behandling blir derfor satt på vent, og den samme doktoren begynner behandling av Ida. (EmergencyPriorityTreatmentUnit)
I denne deloppgaven skal du beskrive eller implementere støtte for disse egenskapene ved å bruke arv. Du finner ikke noe nytt skjelett til denne oppgaven, men du vil finne skjelettet fra del 2 for oppslag. Vi ønsker å ende opp med tre klasser, TreatmentUnit, PriorityTreatmentUnit og EmergencyPriorityTreatmentUnit, som implementerer hver sin logikk i lista over. Forskjellen dem i mellom skal være hvordan de implementerer startTreatment-metodene. De skal være knyttet sammen med arv for å gjøre det enkelt for andre klasser å bytte mellom dem og for å gi god gjenbruk, men detaljene i hvordan arvingsmekanismen brukes skal være opp til deg. Det er lov å innføre ekstra klasser og metoder i arvingshierarkiet, hvis det gjør løsningen bedre. Forklar med tekst og kode hvordan du vil 1) strukturere arvingshierarkiet og 2) hvilke metoder som deklareres/implementeres hvor. Skriv også kode for metodene. Siden fokuset her er mer på objektorientert organisering av kode, vil det også gis poeng for pseudokode.
Expand |
---|
title | Skjelett til del 2 gjentatt for oversikt over metoder |
---|
|
Code Block |
---|
| /**
* A patient has a set of conditions (of type String) that needs to be treated.
*/
public class Patient {
/**
* Indicates if this patient has conditions that needs to be treated.
* @return true if this patient has conditions that needs to be treated,
* false otherwise.
*/
public boolean requiresTreatment() { // 2a
// Implementation hidden
}
}
/**
* A doctor has the capacity to treat one patient at a time.
* The doctor as a list of competencies (of type String) that
* indicates what conditions s/he can treat.
*/
public class Doctor {
/**
* Initialise this doctor with a set of competencies.
* @param competencies
*/
public Doctor(...) { // 2b
// Implementation hidden
}
/**
* Indicates to what extent this doctor can treat the provided patient.
* The value is the number of the patient's conditions this doctor can
* treat divided by the number of conditions the patient has.
* Conditions and competences are matched using simple String comparison.
* @param patient
* @return the ratio of the patient's conditions that this doctor
* can treat.
*/
public double canTreat(final Patient patient) { // 2b
// Implementation hidden
}
/**
* "Treats" the patient by removing all the patient's conditions
* that this doctor can treat.
*/
public void treat() { // 2b
// Implementation hidden
}
/**
* @return the patient this doctor is treating, or null if s/he
* isn't currently treating any patient.
*/
public Patient getPatient() {
// Implementation hidden
}
/**
* @return true if this doctor is currently treating a patient,
* otherwise false.
*/
public boolean isAvailable() {
// Implementation hidden
}
/**
* Sets the patient that this doctor is treating, use null to
* indicate s/he isn't currently treating any patient.
* @param patient
*/
public void setPatient(final Patient patient) {
// Implementation hidden
}
}
/**
* A class for managing a set of doctors and the patients they're treating.
* When doctors or patients arrive, it is made sure that patients are treated
* as soon as possible.
*/
public class TreatmentUnit {
// Internal declaration hidden
/**
* Adds a doctor and makes sure s/he starts treating a patient, if one
* is waiting.
* @param doctor
*/
public void addDoctor(final Doctor doctor) {
// Possible changes
}
/**
* @return the currently available doctors
*/
public Collection<Doctor> getAvailableDoctors() {
// Possible changes
}
/**
* Adds a patient to this treatment unit, and makes sure treatment starts
* if any doctor is available.
* Otherwise the patient is queued for treatment when a doctor becomes
* available.
* @param patient
*/
public void addPatient(final Patient patient) {
// Possible changes
}
/**
* @param pred the predicate that the doctor must satisfy
* @return some doctor satisfying the predicate
*/
public Doctor getDoctor(final Predicate<Doctor> pred) {
// Possible changes
}
/**
* Find the doctor, if any, that treats the provided patient.
* @param patient
* @return the doctor treating the provided patient, or null if the
* patient isn't currently being treated.
*/
public Doctor getDoctor(final Patient patient) {
// Possible changes
}
/**
* Find all patients that are not currently being treated
* @return the patients not currently being treated
*/
public Collection<Patient> getWaitingPatients() {
// Possible changes
}
/**
* Finds a waiting patient and sets him/her as the provided doctor's patient.
* Will only accept a patient that has some condition that the doctor actually
* can treat.
* @param doctor the doctor for which a patient to treat should be found
* @return true if a patient for the provided doctor was found, false
* otherwise.
*/
private boolean startTreatment(final Doctor doctor) {
// Implementation hidden
}
/**
* Finds an available doctor for the provided patient, and sets that doctor to
* treat the patient.
* Will only accept a doctor that actually can treat some condition for the
* provided patient.
* @param patient the patient for which a treating doctor should be found
* @return true if a doctor for the provided patient was found, false
* otherwise.
*/
private boolean startTreatment(final Patient patient) {
// Implementation hidden
}
/**
* Removes the link between doctor and patient, after treatment is finished.
* If the patient is fully treated, s/he is removed from this treatment unit,
* otherwise another round of treatment is initiated.
* Also ensure the doctor starts treating another patient.
* @param doctor the doctor that has finished treating his/her patient
*/
public void treatmentFinished(final Doctor doctor) {
// Implementation hidden
}
}
|
|
Expand |
---|
| TreatmentUnit: Løsningsforslaget viser utvidelse med en abstrakt klasse AbstractTreatmentUnit. Denne klassen implementerer alle metoder som ikke involverte regelsett for hvordan en skulle start behandling, og deklarerer de relevante abstrakte metoden (startTreatment *2). Disse ble så implementert i TreatmentUnit, med løsning akkurat som i del 2. En slik abstrakt klasse er ikke påkrevd, men en god idé, fordi den tydeliggjør hva som er ment å variere (polymorfi) i subklassene. PriorityTreatmentUnit: Her skulle en velge ut den ventende pasienten som hadde høyest prioritet (getPriority). Selv om getPriority ikke ble oppgitt kunne en gjøre antakelser om bruk. Den eneste metoden som måtte implementeres i denne klassen var startTreatment(Doctor), siden prioritering må gjøres hver gang det oppstår en situasjon der pasientene konkurrerer om en doktor som er ankommet eller blitt ledig. Forskjellen fra tidligere implementasjon er at en må gå igjennom alle pasienter (som denne doktoren kan behandle) og lagre den pasienten som til nå har høyest prioritet. Vi har også vist pseudokode som vil være en fullgod besvarelse for denne klassen. EmergencyPriorityTreatmentUnit: Den eneste metoden som trenger ny logikk er startTreatment(Patient). Derfor er det lurt (men strengt tatt ikke nødvendig) å arve fra PriorityTreatmentUnit, siden vi da kan utnytte den eksisterende prioriteringslogikken. Det er jo bare når en ikke finner en doktor med super.startTreatment(patient) at ny logikk for å avbryte pågående behandling er aktuell. Hvis dette er tilfelle, må en gå igjennom alle doktorer (trenger ny hjelpemetode getAllDoctors-metode) og sjekke om denne doktoren kan behandle pasienten. Merk at vi utelater alle ledige doktorer, siden disse allerede er sjekket i kallet til superklassens metode (dette kan forsåvidt skje i den nye hjelpemetoden, som da kanskje bør hete getAllTreatingDoctors). Vi bruker samme logikk som tidligere for å velge ut den lavest prioriterte pasienten. Vi oppdatere dennes nåværende doktor sin pasient til den nye pasienten (getDoctor(patientToSuspend).setPatient(patient)). Til slutt må pasienten som fikk avbrutt behandlingen få en ny sjanse til behandling av en annen lege med et nytt kall til startTreatment. Det er ganske mange ting å huske på, men det viktigste er tross alt god bruk av arv. Også her tillates pseudokode, se eksempel i LF. Merk at oppgaven beskrev klassen PriorityTreatment, mens LF kaller den PriorityTreatmentUnit. Det er selvsagt ikke viktig. Code Block |
---|
| public class PriorityTreatmentUnit extends TreatmentUnit {
protected double getPriority(Patient patient) {
return 0.0;
}
@Override
protected boolean startTreatment(Doctor doctor) {
Patient patient = null;
for (Patient patient2 : getWaitingPatients()) {
if (doctor.canTreat(patient2) > 0.0 && (patient == null || getPriority(patient2) > getPriority(patient))) {
patient = patient2;
}
}
if (patient != null) {
doctor.setPatient(patient);
return true;
}
return false;
}
}
/* PSEUDOKODE-eksempel FOR startTreatment(doctor)
* Går gjennom alle pasienter som venter (getWaitingPatients()) og
* holder rede på den med høyest prioritet (getPriority).
* Sjekker om det finnes en doktor
* med riktig kompetanse (canTreat)
* Hvis man har funnet en pasient som kan behandles,
* så får doktoren denne (setPatient) og true returneres.
*/
public class EmergencyPriorityTreatmentUnit extends PriorityTreatmentUnit {
@Override
public boolean startTreatment(Patient patient) {
if (! super.startTreatment(patient)) {
Patient patientToSuspend = null;
for (Doctor doctor : getAllDoctors()) {
if (doctor.canTreat(patient) > 0.0) {
Patient existingPatient = doctor.getPatient();
if (existingPatient != null && getPriority(existingPatient) < getPriority(patient) &&
(patientToSuspend == null || getPriority(existingPatient) < getPriority(patientToSuspend))) {
patientToSuspend = existingPatient;
}
}
}
if (patientToSuspend != null) {
getDoctor(patientToSuspend).setPatient(patient);
startTreatment(patientToSuspend);
return true;
}
}
return false;
}
} |
Vanlige feil/alternative løsninger: - Selve forståelsen, beskrivelsen og bruken av arv var vanskelig for en god del.
- Noen forstod prioritet som noe måtte legges inn som en ny samling, eller definerte egne eksempler på hva slags tilstander som ga hvilken prioritet. Poenget her var at en skulle bruke getPriority på en pasient for å få ut et tall en kunne sammenlikne med.
- TreatmentUnit: Det var ikke nødvendig å gjøre denne abstrakt, men en måtte forklare at den ville kunne virke som tidligere.
- PriorityTreatmentUnit: Det viktige var at en måtte arve TU, og gitt vår implementasjon måtte en bare endre på startTreatment(doctor) og gå igjennom getWaitingPatients(). En vanlig feil var å ikke gå igjennom alle pasienter for å finne den som kunne behandles nå og som hadde høyest prioritet, men bare returnere når en har funnet en mulig kobling (i lf vist ved oppdatering av patientToSuspend).
- EmergencyPriorityTreatmentUnit: Denne skulle i følge oppgaveteksten ha den samme funksjonaliteten som PriorityTreatmentUnit, men utvide denne. Noen valgte å implementere startTreatment(doctor) til å være lik som i PTU i stedet for å arve denne. Mange glemte at en måtte sjekke om en pasient kunne behandles med vanlig prioritering før en gikk igjennom doktorer som holdt på med behandling. Mange glemte at når en satt en behandlende doktor til å behandle en pasient, da måtte en håndtere pasienten som suspenderes. Denne må legges inn i pasientlisten igjen (hvis en valgte en løsning der pasienter under behandling ikke var i pasientsamlingen) samt at denne pasienten må må en ny startTreatment(patientToSuspend)
- Ved alternative løsnigner løsninger tidligere vil riktig løsning være ulik. Dette gjelder for eksempel når en har endt opp med å gjøre ting som egentlig skulle være i startTreatment i addPatient og addDoctor. Disse løsningene blir da vurdert med bakgrunn i tidligere valg/misforståelser, for å i størt mulig grad unngå følgefeil.(Hit jeg har kommet foreløpig)
- Kode/pseudokode blir gitt poeng avhengig av korrekthet og hvor dypt den går. Overfor finner dere et eksempel på pseudokode for PTU, denne skulle gi full uttelling.
|
|