3. Cake pattern
‘Cake Pattern’ because “(...) beyond my
appreciation of cake, [a] cake is made of a
number of layers (separated by jam), and
can be sliced. The layers represent the
different levels of inner class nesting. It is
conceivable that you would reach the
bottom layer by working your way down
from the top.
http://scala.sygneca.com/patterns/component-mixins
6. class UserRepository {
def authenticate(user: User): User = {
println("authenticating user: " + user)
user
}
def create(user: User): User = {
println("creating user: " + user)
user
}
}
7. class UserService {
val userRepository = new UserRepository
def authenticate(username: String, password: String): User =
userRepository.authenticate(new User(username, password))
def create(username: String, password: String): User =
userRepository.create(new User(username, password))
}
8. class UserRepository {
def authenticate(user: User): User = {
println("authenticating user: " + user)
user
}
def create(user: User): User = {
println("creating user: " + user)
user
}
}
9. trait UserRepositoryComponent {
val userRepository: UserRepository
class UserRepository {
def authenticate(user: User): User = {
println("authenticating user: " + user)
user
}
def create(user: User): User = {
println("creating user: " + user)
user
}
}
}
10. class UserService {
def authenticate(username: String, password: String): User =
userRepository.authenticate(new User(username, password))
def create(username: String, password: String): User =
userRepository.create(new User(username, password))
}
11. trait UserServiceComponent extends
UserRepositoryComponent {
//val userRepository: UserRepository
val userService: UserService
class UserService {
def authenticate(username: String, password: String): User =
userRepository.authenticate(new User(username, password))
def create(username: String, password: String): User =
userRepository.create(new User(username, password))
}
}
12. trait UserServiceComponent {
self: UserRepositoryComponent =>
//val userRepository: UserRepository
val userService: UserService
class UserService {
def authenticate(username: String, password: String): User =
userRepository.authenticate(new User(username, password))
def create(username: String, password: String): User =
self.userRepository.create(new User(username, password))
}
}
13. object ComponentRegistry extends
UserServiceComponent with
UserRepositoryComponent {
val userRepository = new UserRepository
val userService = new UserService
}
val userService = ComponentRegistry.userService
val user = userService.authenticate("user", "password")
// => User(user,password)
14. import org.mockito.Mockito._
class TestingEnvironment extends
UserServiceComponent with
UserRepositoryComponent {
val userRepository = mock(classOf[UserRepository])
val userService = new UserService
}
val testEnv = new TestingEnvironment
when(testEnv.userRepository
.authenticate(new User("user", "password")))
.thenReturn(new User("mock", "mockpwd"))
val userService = testEnv.userService
val user = userService.authenticate("user", "password")
// => User(mock,mockpwd)