In C# its possibly to use AsDynamic to invoke a overloaded method on a subclass (example here) thus allowing an abstract class to invoke methods it does not itself define. Is something similar possible with Scala 2.9 applyDynamic ?. I tried the following
abstract class AggregateRoot extends Dynamic {
def applyChange(event: Event) {
this.applyDynamic("handleEvent")(event)
}
// this does not work
def applyDynamic(name : String)(args: Any*) = this
}
used like this
class InventoryItem extends AggregateRoot {
def handleEvent(event: InventoryItemCreated) {
println("received InventoryItemCreated")
}
def handleEvent(event: InventoryItemDeactivated) {
println("received InventoryItemDeactivated")
}
}
where InventoryItemCreated and InventoryItemDeactivated both are events
class Event;
class InventoryItemDeactivated extends Event;
class InventoryItemCreated extends Event;
I then expect to be able to do something like this
var aggregate : AggregateRoot = new InventoryItem
var event = new InventoryItemDeactivated
aggregate.applyChange(event) // should print "received InventoryItemDeactivated"
but I cannot figure out how to define applyDynamic (in AggregateRoot) so that it can invoke overloaded methods in subclasses at runtime without itself defining them. Other solutions that achieve the same result are welcome (perhaps structural typing can come in handy ?).
Dynamic doesn't gain you anything here because what it does it to let you define the mechanics for handling an undefined method. In your example, however, all methods called are defined.
What you actually want is the mechanics of finding a method defined in the class, and this does not exist, because Dynamic means to be a bridge to other JVM languages, which may implement their "methods" in completely different manners.
All you need to do, however, is use reflection. Scala doesn't have, as of 2.9.1, a reflection library, but Java's good enough for the purpose. Here's how you'd write AggregateRoot:
abstract class AggregateRoot {
def applyChange(event: Event) {
this.getClass.getMethod("handleEvent", event.getClass).invoke(this, event)
}
}
What Dynamic would allow you to do is:
abstract class AggregateRoot extends Dynamic {
def applyDynamic(name : String)(args: Any*) =
this
.getClass
.getMethod(name, args map (_.getClass): _*)
.invoke(this, args map (_.asInstanceOf[Object]): _*)
}
And then do this at the end:
aggregate.handleEvent(event)
Where aggregate, because it is of type AggregateRoot and not InventoryItem, doesn't know it has the method handleEvent. But I suspect this is not what you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With