How can I use Scala's cake pattern to implement robot legs?

674 views Asked by At

My development makes extensive use of the robot legs binding problem. I know how to solve it with PrivateModule in Guice, but it isn't clear how this would be done with Scala's cake pattern.

Could someone explain how this would be done, ideally with a concrete example based off of Jonas Boner's coffee example at the end of his blog post? Maybe with a warmer that could be configured for left and right sides, injected with an orientation and a def isRightSide?

1

There are 1 answers

0
Przemek Pokrywka On

Cake pattern doesn't solve this problem in its original form. You have several choices how to deal with that. The solution I prefer is to create each "robot leg" by calling its constructor with appropriate parameter - code shows that better, than words.

I think the answer cited above is more readable, but if you are already familiar with Jonas' example, here is how you'd make Warmer configurable with an orientation:

// =======================
// service interfaces
trait OnOffDeviceComponent {
  val onOff: OnOffDevice
  trait OnOffDevice {
    def on: Unit
    def off: Unit
  }
}
trait SensorDeviceComponent {
  val sensor: SensorDevice
  trait SensorDevice {
    def isCoffeePresent: Boolean
  }
}

// =======================
// service implementations
trait OnOffDeviceComponentImpl extends OnOffDeviceComponent {
  class Heater extends OnOffDevice {
    def on = println("heater.on")
    def off = println("heater.off")
  }
}
trait SensorDeviceComponentImpl extends SensorDeviceComponent {
  class PotSensor extends SensorDevice {
    def isCoffeePresent = true
  }
}
// =======================
// service declaring two dependencies that it wants injected
trait WarmerComponentImpl {
  this: SensorDeviceComponent with OnOffDeviceComponent =>

  // Note: Warmer's orientation is injected by constructor.
  // In the original Cake some mixed-in val/def would be used
  class Warmer(rightSide: Boolean) {
    def isRightSide = rightSide
    def trigger = {
      if (sensor.isCoffeePresent) onOff.on
      else onOff.off
    }
  }
}

// =======================
// instantiate the services in a module
object ComponentRegistry extends
  OnOffDeviceComponentImpl with
  SensorDeviceComponentImpl with
  WarmerComponentImpl {

  val onOff = new Heater
  val sensor = new PotSensor
  // Note: now we need to parametrize each particular Warmer
  // with its desired orientation
  val leftWarmer = new Warmer(rightSide = false)
  val rightWarmer = new Warmer(rightSide = true)
}

// =======================
val leftWarmer = ComponentRegistry.leftWarmer
leftWarmer.trigger