Skip to content
Snippets Groups Projects
Commit 05a48e0c authored by kiady.arintsoa's avatar kiady.arintsoa :man_with_turban_tone2:
Browse files

Add ex4

parent fc24fd50
No related branches found
No related tags found
No related merge requests found
package ex2
// Create a class model of the hospital including the following:
// units
// doctors
......
package ex4
// Create a class model of the hospital including the following:
// units
// doctors
// patients
// Create methods relative to these classes e.g.
// create consultation
// reserve appointment
// Include one use of Type Restriction, why is it useful?
// Include one example of Covariance and one of Contravariance, why are they useful?
enum Expertise {
case Cardiology
case Surgery
case Endocrinology
case Neurology
case Ophthalmology
case Pediatrics
case Psychiatry
case Urology
}
extension (s: String)
def isName: Boolean = s.matches("[A-Z][a-z]+")
trait Person {
val name: String
var age: Int
}
class Doctor(val name: String, var age: Int, val expertises: List[Expertise])
extends Person {
def consult(patient: Patient)(using hospital: Hospital) =
println(s"Doctor $name is consulting patient ${patient.name}" +
s"with condition ${patient.condition}.")
given Conversion[Doctor, Patient] = (d: Doctor) => Patient("mental", d.name, d.age)
}
case class Patient(condition: String, val name: String, var age: Int)
extends Person {
def requestAppointment(using hospital: Hospital) = {
val unit =
hospital.units.find(u =>
u.areaOfExpertise == hospital.processCondition(this.condition)
)
if unit.isDefined then unit.get.addPatient(this)
else throw Exception("No unit available for this condition.")
}
}
// Covariance is useful here because a list of doctors is a list of persons
// and we might want to use a list of doctors in a method that expects a list of persons
// Type restriction is useful here because we want to restrict the type of the list to only Doctors
case class UnitPersonnel[+T <: Doctor](list: List[T])
class HospitalUnit(
var areaOfExpertise: Expertise,
var doctors: UnitPersonnel[Doctor],
var patients: List[Patient]
) {
def assignDoctor(doctor: Doctor): Unit = doctors = UnitPersonnel(
doctors.list :+ doctor
)
def addPatient(patient: Patient)(using hospital: Hospital) = {
patients = patients :+ patient
doctors.list.last.consult(patient)
}
}
// Contravariance is useful here because we might create summaries of generic types
abstract class SummaryPrinter[-T]:
def printSummary(value: T): String
class Hospital {
var units: List[HospitalUnit] = List()
var doctors: List[Doctor] = List()
def processCondition(condition: String) = condition match {
case "heart" => Expertise.Cardiology
case "brain" => Expertise.Neurology
case "eye" => Expertise.Ophthalmology
case "kidney" => Expertise.Urology
case "bone" => Expertise.Surgery
case "endocrine" => Expertise.Endocrinology
case "child" => Expertise.Pediatrics
case "mental" => Expertise.Psychiatry
case _ => Expertise.Surgery
}
def addDoctor(d: Doctor): Unit = {
if !d.name.isName then throw Exception("Invalid name.")
for expertise <- d.expertises do {
val unit = units.find(_.areaOfExpertise == expertise)
if unit.isDefined then {
doctors = doctors :+ d
unit.get.assignDoctor(d)
return
}
}
addUnit(d.expertises.head, d)
}
def addUnit(expertise: Expertise, doctor: Doctor) = {
val unit =
new HospitalUnit(
expertise,
UnitPersonnel[Doctor](List(doctor)),
List()
)
units = units :+ unit
}
def listDoctors = doctors.foreach(PersonSummaryPrinter.printSummary(_))
object PersonSummaryPrinter extends SummaryPrinter[Person]():
def printSummary(person: Person): String =
s"${person.name} is ${person.age} years old."
}
package ex4
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
class Ex4Spec extends AnyWordSpec with Matchers {
"An hospital" should {
val hospital = new Hospital
given Hospital = hospital
"have a list of units" in {
hospital.units should be(List())
}
"have a list of doctors" in {
hospital.doctors should be(List())
}
"accept new doctors" in {
val doctor = new Doctor("John", 30, List(Expertise.Cardiology))
hospital.addDoctor(doctor)
hospital.units should have length 1
}
"accept appointments" in {
val patient = Patient("heart", "John", 30)
patient.requestAppointment
hospital.units.head.patients should have length 1
}
"throw an exception if doctor name is invalid" in {
val doctor = new Doctor("23864", 30, List(Expertise.Cardiology))
an[Exception] should be thrownBy {
hospital.addDoctor(doctor)
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment