Cake Pattern, Self Types and Realistic Example
09 April 2014 Comments off
Reading time:
2 minutes
Word count:
407
Original drafted 17 March 2014 for an incomplete article.
The Cake pattern for Scala using a flaming cake as well.
This is the quasi-production code:
package uk.co.xenonique.learning.cake
/**
* The type Cake
*
* @author Peter Pilgrim
*/
class Cake(val name: String) {
def inspect(): String = {
name
}
}
trait Oven {
def powerUp(): Unit
def powerDown(): Unit
}
trait CakeMaker {
def bake( cake: Cake )
}
trait CakeFactory {
def produce( cakes: List[Cake] )
}
class CakeFactoryImpl extends CakeFactory {
this: CakeMaker with Oven =>
override def produce( cakes: List[Cake] ): Unit = {
powerUp()
for ( c <- cakes) {
bake(c)
}
powerDown()
}
}
This is the learning test code:
package uk.co.xenonique.learning.cake
import org.scalatest.WordSpec
import org.scalatest.matchers.MustMatchers
import org.scalatest.mock.MockitoSugar
/**
* The type CakeSpec
*
* @author Peter Pilgrim
*/
class CakeSpec extends WordSpec with MockitoSugar with MustMatchers {
trait Baker extends CakeMaker {
override def bake(cake: Cake): Unit = {
println(s"I'm a baker, baking a cake: "+cake.inspect())
}
}
trait IndustrialOven extends Oven {
override def powerUp() = {
println("firing up the oven")
}
override def powerDown() = {
println("venting the oven")
}
}
"Cake" should {
"understand the cake pattern" in {
val factory = new CakeFactoryImpl() with Baker with IndustrialOven {
}
val cakes = List( new Cake("Battenburg"), new Cake("Cherry Madeira"), new Cake("Lemon and Lime"))
factory.produce(cakes)
}
}
}
Assuming that you know what you are doing: insert this code into a test Scala project with a decent IDE. Run the test should demonstrate the results.
What is the benefit of this so-called Cake Pattern? Well in short, Scala allows self-type with multiple traits (the dependencies). See the definition of CakeFactoryImpl, which expresses a dependency on the type CakeMaker and an Oven traits being mixed-in to the final concrete class. In other words, the final CakeFactoryImpl is a type of CakeMaker (Baker) and also it is type of Oven (IndustrialOven). Therefore, it is a small exercise to write mock objects with these traits, hence the reason I demonstrated with the pattern using a ScalaTest. In fact, it is an exercise to the reader, to write Mockito mocks of this CakeFactoryImpl. Imagine if your Oven was a reference, wrapper or connection pool to a database.
Finally, to understand the cake pattern you have to comprehend the Scala self-types and annotations. Personally, I found this pattern a little convoluted, because of the traits tend to have partial implementations in a production work.