The previous approach has most of the logic in our context. You may sometimes see a different approach, which is valid as your context grows bigger.
In this approach, Snail would become really thin:
class Snail {
internal var mood: Mood = Still(this)
private var healthPoints = 10
// That's all!
}
Note that we marked mood as internal. That lets other classes in that package alter it.
Instead of Snail implementing WhatCanHappen, our Mood will:
sealed class Mood : WhatCanHappen
And now the logic resides within our state objects:
class Still(private val snail: Snail) : Mood() {
override fun seeHero() = snail.mood.run {
Aggressive(snail)
}
override fun getHit(pointsOfDamage: Int) = this
override fun timePassed() = this
}
Note that our state objects now receive a reference to their context in the constructor.
That's the first time we've met the run extension function. It's equivalent would be:
override fun seeHero(): Mood {
snail.mood = Aggressive(snail)
return snail.mood
}
By using run, we can preserve the same logic, but omit the function body.
You'll need to decide what approach to use. In our example, this will actually produce much more code, will have to implement all the methods by itself.