I have the following implementation of a "Player".
// interface for a player
trait Player {
def jump(): Unit
def swim(): Unit
}
// a beginner player can't jump nor swim
class Beginner extends Player {
def jump(): Unit = throw Error()
def swim(): Unit = throw Error()
}
// movement decorator abstraction
abstract class MovementDecorator(my_player: Player) extends Player {
}
// concrete decorator
class Swim(player_x: Player) extends MovementDecorator(player_x) {
def jump(): Unit = throw new Error("I can't jump")
override def swim(): Unit = println("I swam!")
}
// concrete decorator
class Jump(player_x: Player) extends MovementDecorator(player_x) {
override def jump(): Unit = println("I jumped!")
def swim(): Unit = throw new Error("I can't swim")
}
A concrete Player
(i.e. Beginner
) can't have methods such as jump()
or swim()
. But I can decorate aka wrap the object with the Swim
and/or Jump
classes to give the Beginner
that capability.
However, when I run the main method, I get the outputs shown with comments.
@main
def main(): Unit = {
val swimmer = Swim(Beginner())
swimmer.swim() // "I swam!"
val jumper = Jump(Beginner())
jumper.jump() // "I jumped!"
val swimmer_jumper = Jump(Swim(Beginner()))
swimmer_jumper.jump() // "I jumped!"
swimmer_jumper.swim() // Exception at Jump.swim: I can't swim
}
I want to keep the following to create my object
val swimmer_jumper = Jump(Swim(Beginner()))
Is there a specific way of overriding methods that I'm missing? I thought when you override a method it overrides any other method of the object -- and it becomes the preferred one.
CodePudding user response:
You need to modify your MovementDecorator
to delegate the implementation to the decorated instance of Player
:
// movement decorator abstraction
abstract class MovementDecorator(my_player: Player) extends Player {
override def swim(): Unit = my_player.swim()
override def jump(): Unit = my_player.jump()
}
And then in the MovementDecorator
inheritors override only corresponding methods:
// concrete decorator
class Swim(player_x: Player) extends MovementDecorator(player_x) {
override def swim(): Unit = println("I swam!")
}
// concrete decorator
class Jump(player_x: Player) extends MovementDecorator(player_x) {
override def jump(): Unit = println("I jumped!")
}
Demo.