Home > Net >  How to properly override a method in Scala?
How to properly override a method in Scala?

Time:12-16

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.

  • Related