Skip to content

Instantly share code, notes, and snippets.

@holyjak
Last active December 28, 2015 15:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save holyjak/7519799 to your computer and use it in GitHub Desktop.
Save holyjak/7519799 to your computer and use it in GitHub Desktop.
[Surfacing Hidden Design: A Better Alternative To Interrelated Mutable Fields](http://wp.me/p3ui6n-1q) - 1) Explicit and defect-preventing expression of the states and transitions
def randomBelow = ...
/** When should the health state change and what to */
class HealthChange(val time: Int, val newHealth: Health) {
def immediate = (time == 0)
}
/** The root of the health hierarchy; the health (i.e. infection) evolves in stages */
sealed abstract class Health(val infectious: Boolean, val visiblyInfectious: Boolean) {
def evolve(): Option[HealthChange] // returns None if no further change possibly/expected
}
/** In some stages the person is infected but it isn't visible*/
sealed abstract class CovertlyInfected extends Health(infectious = true, visiblyInfectious = false) {}
/** In other stages the person is infected and it is clearly visible*/
sealed abstract class VisiblyInfected extends Health(infectious = true, visiblyInfectious = true) {}
case object HEALTHY extends Health(infectious = false, visiblyInfectious = false) {
def evolve() = // 40% chance of getting infected, triggered on meeting an infected person
if (randomBelow(101) <= 40/*%*/)
Some(new HealthChange(0, INCUBATIOUS))
else
None // no change, stays healthy
}
case object INCUBATIOUS extends CovertlyInfected {
def evolve() = // After 6 days if infection without visible effects becomes sick
Some(new HealthChange(6, SICK))
}
case object SICK extends VisiblyInfected {
def evolve() = // die with 25% on day 14 or stays sick for 2 more days, then immune
if (randomBelow(101) <= 25/*%*/)
Some(new HealthChange(14 - 6, DEAD))
else
Some(new HealthChange(16 - 6, IMMUNE))
}
case object DEAD extends VisiblyInfected {
def evolve() = None // Dead people stay dead
}
/** The symptoms have disappeared but the person can still infect others for 2 more days */
case object IMMUNE extends CovertlyInfected {
def evolve() =
Some(new HealthChange(18 - 16, HEALTHY))
}
class Person (val id: Int, var health: Health = HEALTHY) {
def tryInfect() { // upon meeting an infected person
if (health != HEALTHY) throw new IllegalStateException("Only healthy can be infected")
health.evolve().foreach(
healthChng => setHealth(healthChng.newHealth) // infection happens immediately
)
}
/** Set the new health stage and schedule the next health change, if any */
def setHealth(h: Health) {
this.health = h
h.evolve().foreach(hNext => {
if (hNext.immediate)
setHealth(hNext.newHealth)
else
afterDelay(hNext.time) {setHealth(hNext.newHealth)}
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment