* Упражнение 10, 2015 – добавка
Публикувано на 01 декември 2015 в раздел ПИК3 Java.
Тук представям разширен вариант на задачата от упражнение 10. На практика са решени всички поставени допълнителни задачи. Кода на много места може да се изчисти и да стане по-лесно четим, но се надявам и така да е достатъчно разбираем. Вмъкнати са следните допълнителни функционалности, които подобряват предишната задача:
- GPOffice вече е самостоятелен клас;
- Създаден е клас Report. При всяко посещение в стая с лекар за пациента се изготвя доклад за извършената дейност. После обратно в GPOffice докладите се сливат в един общ (метод mergeWith). За целта е променена логиката на метод nextPatient() - вече връща доклад за следващия пациент;
- Няма хвърляне на изключения и не се утежняваме с try-catch блокове;
- MedicalRoom и HospitalRoom вече са наследници на клас Room, с което структурата им става по-ясна;
- Вече можете да вкарвате всякакви диагнози на пациенти, а не само предварително дефинираните. В MedicalRoom и HospitalRoom ще бъдат лекувани само тези болести, които са възможни (possibleCures), а непознатите няма да бъдат разглеждани;
- Две болести (Diagnosis) приемаме за еднакви, ако имената им съвпадат - не обръщаме внимание на цените. Тоест ако даден пациент е болен от болест A и си мисли, че тя струва X лева, това не значи, че в болницата ще му струва толкова - може да е по-евтино или по-скъпо. Реализирано е по този начин, защото се стремих да намаля количеството код. Реално в масива с болести на пациента (sicknesses) не е нужно да се пази цената, а само името на болестта, но в случая преизползвах вече готовия клас (което следва и по наследство от решението на оригиналната задача);
- Двама пациента приемаме за еднакви, ако са с едно и също име и ЕГН. Заболяванията им и болестите им не се взимат под внимание при сравнение на обекти;
- GPOffice няма опашка с пациенти - такива има само при MedicalRoom и HospitalRoom. За опашката пред GPOffice се грижи main метода;
- Пазим дълга (debt) на пациентите на две места - веднъж в репорта му в GPOffice и веднъж в статичния ArrayList debtors. За конкретната програма не е необходимо това дублиране на информация, но го запазих заради продължението от предишната задача.
Решение:
Debtor.java:
package upr11;
public class Debtor{
Patient patient;
Double debt;
Debtor(Patient patient, Double debt){
this.patient = patient;
this.debt = debt;
}
}
Diagnosis.java:
package upr11;
public class Diagnosis{
double cost;
String name;
public Diagnosis(double cost, String name){
this.cost = cost;
this.name = name;
}
public int hashCode(){
int result = 17;
result = result*37 + this.name==null?0:this.name.hashCode();
return result;
}
public boolean equals(Object o){
if(!(o instanceof Diagnosis)) return false;
String name = ((Diagnosis)o).name;
if(this.name.equals(name)) return true;
else return false;
}
}
GPOffice.java:
package upr11;
import java.util.HashMap;
import java.util.Map;
public class GPOffice{
MedicalRoom mr;
HospitalRoom hr;
HashMap<Patient, Report> reports;
public GPOffice(MedicalRoom mr, HospitalRoom hr){
this.mr = mr;
this.hr = hr;
this.reports = new HashMap<>();
}
// Queues patient to a Room if we can cure him
boolean nextPatient(Patient p){
// First the serious sicknesses for HospitalRoom
for(Diagnosis ps: p.sicknesses){
if(hr.cures(ps)){
hr.queuePatient(p);
return true;
}
}
// If not, check for MedicalRoom sicknesses
for(Diagnosis ps: p.sicknesses){
if(mr.cures(ps)){
mr.queuePatient(p);
return true;
}
}
// If not, we cannot queue him anywhere
return false;
}
void logReport(Patient p, Report r){
Report old = this.reports.get(p);
if(old!=null){
old.mergeWith(r);
this.reports.put(p, old);
}
else this.reports.put(p, r);
}
void printReports(){
for(Map.Entry<Patient, Report> es : this.reports.entrySet()){
es.getValue().print();
}
}
}
Patient.java:
package upr11;
import java.util.Set;
import java.util.HashSet;
import java.util.HashMap;
import java.util.List;
import java.util.Iterator;
public class Patient{
final String name;
final String egn;
double paycheck;
HashSet<Diagnosis> sicknesses;
Patient(String name, String egn, double paycheck, Set<Diagnosis> sicknesses){
this.name = name;
this.egn = egn;
this.paycheck = paycheck;
this.sicknesses = new HashSet<>(sicknesses);
}
Patient(String name, String egn, double paycheck, List<Diagnosis> sicknesses){
this.name = name;
this.egn = egn;
this.paycheck = paycheck;
this.sicknesses = new HashSet<>(sicknesses);
}
double payBill(double amount){
this.paycheck -= amount;
if(this.paycheck >= 0) return 0;
else{
double debt = -this.paycheck;
this.paycheck = 0;
return debt;
}
}
boolean isSick(){
return !this.sicknesses.isEmpty();
}
boolean isSickFrom(Diagnosis sickness){
return this.sicknesses.contains(sickness);
}
public int hashCode(){
int result = 17;
result = result*37 + this.name==null?0:this.name.hashCode();
result = result*37 + this.egn==null?0:this.egn.hashCode();
return result;
}
public boolean equals(Object o){
if(!(o instanceof Patient)) return false;
Patient p = (Patient)o;
if(this.name == p.name
&&
this.egn == p.egn
) return true;
else return false;
}
}
Report.java:
package upr11;
public final class Report{
final Patient patient;
String message;
double debt;
Report(Patient p){
this.patient = p;
this.message = "";
this.debt = 0.0;
}
public Report(Patient patient, String message, double debt){
this.patient = patient;
this.message = message;
this.debt = debt;
}
// Merges reports. True on success.
boolean mergeWith(Report r){
if(!this.patient.equals(r.patient)) return false;
this.debt += r.debt;
if(this.message.equals("")) this.message += r.message;
else this.message += "\n> "+r.message;
return true;
}
void print(){
System.out.println("Report for: "+this.patient.name);
if(!this.message.equals("")) System.out.println("> "+this.message);
else System.out.println("> No messages from doctors");
System.out.print("> List of current sicknesses: ");
if(this.patient.isSick()){
for(Diagnosis s: this.patient.sicknesses) System.out.print(s.name+"; ");
}
else{
System.out.print("COMPLETELY CURED. HOORAY!");
}
System.out.println("\n> Report debt: "+this.debt);
System.out.println("End report for:"+this.patient.name);
}
}
Room.java:
package upr11;
import java.util.LinkedList;
import java.util.HashMap;
public abstract class Room{
int number;
String doctor;
LinkedList<Patient> queue;
Diagnosis[] possibleCures;
protected Room(int number, String doctor, Diagnosis[] possibleCures) {
this.number = number;
this.doctor = doctor;
this.queue = new LinkedList<>();
this.possibleCures = possibleCures;
}
// Shows if room cures certain sickness
boolean cures(Diagnosis sickness){
for(Diagnosis pc: this.possibleCures){
if(pc.equals(sickness)) return true;
}
return false;
}
// Cures patient from the sickness.
// True on success and False if patient is not sick from sickness
private boolean curePatient(Patient patient, Diagnosis sickness)
throws RuntimeException{
if(patient == null || sickness == null){
throw new RuntimeException("Invalid call to curePatient");
}
return patient.sicknesses.remove(sickness);
}
// Cures next patient from the queue
// Writes report and returns it
// or returns null if the queue was empty
Report nextPatient(){
Patient p = null;
// Cleans the queue from possible null elements
// Assigns valid Patient or returns null on empty queue
do{
if(this.queue.isEmpty()) return null;
p = this.queue.getFirst();
this.queue.removeFirst();
}
while(p == null);
Report r = new Report(p);
// Examines the patient for all known Diagnosis
for(Diagnosis sickness: possibleCures){
StringBuilder reportMessage = new StringBuilder();
double debt = 0.0;
// If patient is not sick from the current sickness, check next one
if(!p.sicknesses.contains(sickness)) continue;
// If Patient has no more money, we stop any cures
if(p.paycheck<=0){
reportMessage.append("Room "+this.number+", doctor "+this.doctor+": ");
reportMessage.append("Patient is out of money. Can't cure "+sickness.name);
break;
}
else{
// Patient pays
debt += p.payBill(sickness.cost);
// We cure him
boolean cureResult = this.curePatient(p, sickness);
reportMessage.append("Room "+this.number+", doctor "+this.doctor+": ");
if(cureResult == true) reportMessage.append("Cured from "+sickness.name);
else reportMessage.append("Not cured from "+sickness.name+". Bug?");
}
r.mergeWith(new Report(p, reportMessage.toString(), debt));
}
return r;
}
void queuePatient(Patient p){
this.queue.addLast(p);
}
boolean hasMorePatients(){
return !this.queue.isEmpty();
}
}
class MedicalRoom extends Room{
MedicalRoom(int number, String doctor){
super(number, doctor, new Diagnosis[2]);
super.possibleCures[0] = new Diagnosis(50.0, "Not sick");
super.possibleCures[1] = new Diagnosis(100.0, "Little sick");
}
}
class HospitalRoom extends Room{
HospitalRoom(int number, String doctor){
super(number, doctor, new Diagnosis[2]);
super.possibleCures[0] = new Diagnosis(150.0, "Sick");
super.possibleCures[1] = new Diagnosis(200.0, "Very sick");
}
}
Upr11.java:
package upr11;
import java.util.ArrayList;
import java.util.HashSet;
public class Upr11{
private static ArrayList<Debtor> debtors = new ArrayList<Debtor>();
static void addDebtor(Debtor d){
debtors.add(d);
}
static void printDebtors(){
for(Debtor d: debtors){
System.out.println(d.patient.name + " owes " + d.debt);
}
}
public static void main(String[] args) {
MedicalRoom mr = new MedicalRoom(1, "Ivan Ivanov");
HospitalRoom hr = new HospitalRoom(2, "Petar Petrov");
GPOffice gp = new GPOffice(mr, hr);
ArrayList<Diagnosis> combination1 = new ArrayList<>();
combination1.add(mr.possibleCures[0]);
combination1.add(hr.possibleCures[1]);
Patient p1 = new Patient("Ivan", "1234", 50.0, combination1);
ArrayList<Diagnosis> combination2 = new ArrayList<>();
combination2.add(mr.possibleCures[1]);
combination2.add(hr.possibleCures[0]);
combination2.add(hr.possibleCures[1]);
Patient p2 = new Patient("Petar", "5678", 1000.0, combination2);
ArrayList<Diagnosis> combination3 = new ArrayList<>();
combination3.add(mr.possibleCures[0]);
Patient p3 = new Patient("Maria", "9012", 100.0, combination3);
ArrayList<Diagnosis> combination4 = new ArrayList<>();
combination4.add(mr.possibleCures[0]);
combination4.add(new Diagnosis(500.0, "Unknown condition"));
Patient p4 = new Patient("Todor", "9012", 100.0, combination4);
gp.nextPatient(p1);
gp.nextPatient(p2);
gp.nextPatient(p3);
gp.nextPatient(p4);
// First pass HospitalRoom
while(hr.hasMorePatients()){
Report r = hr.nextPatient();
if(r.debt>0) addDebtor(new Debtor(r.patient, r.debt));
gp.logReport(r.patient, r);
if(r.patient.isSick() && r.patient.paycheck>0) mr.queuePatient(r.patient);
}
// First pass MedicalRoom
while(mr.hasMorePatients()){
Report r = mr.nextPatient();
if(r.debt>0) addDebtor(new Debtor(r.patient, r.debt));
gp.logReport(r.patient, r);
}
gp.printReports();
System.out.println("-------------------");
printDebtors();
}
}
Добави коментар