Skip to content

Instantly share code, notes, and snippets.

@GeePawHill
Created November 19, 2022 20:11
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GeePawHill/2d7f188c0da37354b9f3e52da327f5e4 to your computer and use it in GitHub Desktop.
Save GeePawHill/2d7f188c0da37354b9f3e52da327f5e4 to your computer and use it in GitHub Desktop.
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import kotlin.reflect.KClass
import kotlin.reflect.full.isSuperclassOf
/*
Marker interface. Anything that's a message can be sent across the wire.
*/
interface Message
/*
Things are all the things currently derived from SpaceObject. They will all have to implment
register. There is no further class hierarchy requirement.
*/
interface Thing {
fun register(dispatcher: Dispatcher)
}
/*
This fills the role currently held by Transaction. Add any API you want. For POC, it just collects texts.
*/
class Accumulator {
val texts = mutableListOf<String>()
fun add(text: String) {
texts.add(text)
}
}
interface Receiver {
fun dispatch(message: Message, accumulator: Accumulator)
}
class TypedReceiver<MESSAGE_TYPE : Message>(
val clazz: KClass<*>,
val handler: (message: MESSAGE_TYPE, accumulator: Accumulator) -> Unit
) :
Receiver {
override fun dispatch(message: Message, accumulator: Accumulator) {
if (clazz.isInstance(message) || clazz.isSuperclassOf(message::class)) {
val downcast = message as MESSAGE_TYPE
handler(downcast, accumulator)
}
}
}
class Dispatcher {
val receivers = mutableListOf<Receiver>()
fun <MESSAGE_TYPE : Message> subscribe(
clazz: KClass<MESSAGE_TYPE>,
handler: (other: MESSAGE_TYPE, accumulator: Accumulator) -> Unit
) {
receivers += TypedReceiver(clazz, handler)
}
fun <MESSAGE_TYPE : Message> receive(message: MESSAGE_TYPE, accumulator: Accumulator) {
receivers.forEach { it.dispatch(message, accumulator) }
}
}
class Interactor<THING_TYPE : Thing>(val item: THING_TYPE) {
val dispatcher = Dispatcher()
init {
item.register(dispatcher)
}
fun receive(message: Message, accumulator: Accumulator) {
dispatcher.receive(message, accumulator)
}
}
class Smalltalk {
val objects = mutableListOf<Interactor<*>>()
fun sendAll(message: Message, accumulator: Accumulator) {
objects.forEach { it.receive(message, accumulator) }
}
fun add(thing: Thing): Interactor<*> {
val interactor = Interactor(thing)
objects.add(interactor)
return interactor
}
fun send(interactor: Interactor<*>, message: Message, accumulator: Accumulator) {
interactor.receive(message, accumulator)
}
}
data class DrawMessage(val drawer: Int) : Message
data class ScoreMessage(val score: Int) : Message
class ScoreThing(val score: Int) : Thing {
override fun register(dispatcher: Dispatcher) {
}
}
class ScoreKeeperThing() : Thing {
var total = 0
override fun register(dispatcher: Dispatcher) {
dispatcher.subscribe(ScoreMessage::class, this::score)
dispatcher.subscribe(DrawMessage::class) { message, accumulator ->
accumulator.add("ScoreKeeperThing drew!")
}
}
fun score(message: ScoreMessage, accumulator: Accumulator) {
accumulator.add("ScoreKeeperThing got a score ${message.score}.")
total += message.score
}
}
class SmalltalkTest {
val smalltalk = Smalltalk()
val accumulator = Accumulator()
@Test
fun `Send a draw message to everyone`() {
smalltalk.add(ScoreKeeperThing())
smalltalk.add(ScoreThing(100))
smalltalk.sendAll(DrawMessage(1), accumulator)
// only ScoreKeeper is interested in drawing.
assertThat(accumulator.texts).containsExactly("ScoreKeeperThing drew!")
}
@Test
fun `Send a score message just to the scorekeeper`() {
val scoreKeeper = smalltalk.add(ScoreKeeperThing())
smalltalk.send(scoreKeeper, ScoreMessage(100), accumulator)
assertThat(accumulator.texts).containsExactly("ScoreKeeperThing got a score 100.")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment