Last active
December 28, 2015 15:09
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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