蛋糕图案——为什么这么复杂
cake pattern - why is it so complicated
我正在学习蛋糕的图案。
我正在阅读 this 关于它的博客。
该博客中的示例代码是:
case class User (name:String,email:String,supervisorId:Int,firstName:String,lastName:String)
trait UserRepository {
def get(id: Int): User
def find(username: String): User
}
trait UserRepositoryComponent {
def userRepository: UserRepository
trait UserRepository {
def get(id: Int): User
def find(username: String): User
}
}
trait Users {
this: UserRepositoryComponent =>
def getUser(id: Int): User = {
userRepository.get(id)
}
def findUser(username: String): User = {
userRepository.find(username)
}
}
trait UserInfo extends Users {
this: UserRepositoryComponent =>
def userEmail(id: Int): String = {
getUser(id).email
}
def userInfo(username: String): Map[String, String] = {
val user = findUser(username)
val boss = getUser(user.supervisorId)
Map(
"fullName" -> s"${user.firstName} ${user.lastName}",
"email" -> s"${user.email}",
"boss" -> s"${boss.firstName} ${boss.lastName}"
)
}
}
trait UserRepositoryComponentImpl extends UserRepositoryComponent {
def userRepository = new UserRepositoryImpl
class UserRepositoryImpl extends UserRepository {
def get(id: Int) = {
???
}
def find(username: String) = {
???
}
}
}
object UserInfoImpl extends
UserInfo with
UserRepositoryComponentImpl
我可以通过删除 Users
:
来简化该代码
package simple {
case class User(name: String, email: String, supervisorId: Int, firstName: String, lastName: String)
trait UserRepository {
def get(id: Int): User
def find(username: String): User
}
trait UserRepositoryComponent {
def userRepository: UserRepository
trait UserRepository {
def get(id: Int): User
def find(username: String): User
}
}
trait UserInfo {
this: UserRepositoryComponent =>
def userEmail(id: Int): String = {
userRepository.get(id).email
}
def userInfo(username: String): Map[String, String] = {
val user = userRepository.find(username)
val boss = userRepository.get(user.supervisorId)
Map(
"fullName" -> s"${user.firstName} ${user.lastName}",
"email" -> s"${user.email}",
"boss" -> s"${boss.firstName} ${boss.lastName}"
)
}
}
trait UserRepositoryComponentImpl extends UserRepositoryComponent {
def userRepository = new UserRepositoryImpl
class UserRepositoryImpl extends UserRepository {
def get(id: Int) = {
???
}
def find(username: String) = {
???
}
}
}
object UserInfoImpl extends
UserInfo with
UserRepositoryComponentImpl
}
它编译得很好。
1) 为什么博客里的代码这么复杂?
2) 这是使用蛋糕图案的惯用方式吗?
3) 为什么在这个例子中需要 Users
class?
4) 蛋糕图案应该是这样的吗(看起来没必要Users
class?
5) 还是简化版就好了?
乍一看它可能看起来很复杂,但一旦您熟悉了该模式,它就会……千篇一律且繁琐。对于您的每项服务,您都必须创建一个附带的组件来包装该服务。因此,在提供的示例中,您有一个被 UserRepositoryComponent
包裹的 UserRepository
。这只是抽象,因此您需要对组件和服务都有具体的实现(即 UserRepositoryComponentImpl
包装 UserRepositoryImpl
)。到目前为止,您只有一项服务可能会在您的模块中使用,想象一下创建数十项服务所付出的努力 ;)
是的,这是使用该模式的惯用方式。然而,该模式还有其他变体,例如thin cake pattern
或 parfait
(Dick Wall 创造的术语)
你问的是 User
,但你的代码简化是删除 Users
,所以我将描述它们。 User
是一个简单的案例 class,应该使该示例更 accessible/easier 易于掌握。 Users
然而这里没有必要(它只是另一个中间抽象级别),在我看来它们给示例带来了一些不必要的干扰。
我会说你的简化版本准确地显示了蛋糕图案应该是什么样子。你有一个抽象 UserRepository
包裹在 UserRepositoryComponent
中,你有这两个特征的具体实现,并且你有一些服务 (UserInfo
) 需要用户的存储库(这是 "injected" using self-type annotation).
已回答。
我正在学习蛋糕的图案。
我正在阅读 this 关于它的博客。
该博客中的示例代码是:
case class User (name:String,email:String,supervisorId:Int,firstName:String,lastName:String)
trait UserRepository {
def get(id: Int): User
def find(username: String): User
}
trait UserRepositoryComponent {
def userRepository: UserRepository
trait UserRepository {
def get(id: Int): User
def find(username: String): User
}
}
trait Users {
this: UserRepositoryComponent =>
def getUser(id: Int): User = {
userRepository.get(id)
}
def findUser(username: String): User = {
userRepository.find(username)
}
}
trait UserInfo extends Users {
this: UserRepositoryComponent =>
def userEmail(id: Int): String = {
getUser(id).email
}
def userInfo(username: String): Map[String, String] = {
val user = findUser(username)
val boss = getUser(user.supervisorId)
Map(
"fullName" -> s"${user.firstName} ${user.lastName}",
"email" -> s"${user.email}",
"boss" -> s"${boss.firstName} ${boss.lastName}"
)
}
}
trait UserRepositoryComponentImpl extends UserRepositoryComponent {
def userRepository = new UserRepositoryImpl
class UserRepositoryImpl extends UserRepository {
def get(id: Int) = {
???
}
def find(username: String) = {
???
}
}
}
object UserInfoImpl extends
UserInfo with
UserRepositoryComponentImpl
我可以通过删除 Users
:
package simple {
case class User(name: String, email: String, supervisorId: Int, firstName: String, lastName: String)
trait UserRepository {
def get(id: Int): User
def find(username: String): User
}
trait UserRepositoryComponent {
def userRepository: UserRepository
trait UserRepository {
def get(id: Int): User
def find(username: String): User
}
}
trait UserInfo {
this: UserRepositoryComponent =>
def userEmail(id: Int): String = {
userRepository.get(id).email
}
def userInfo(username: String): Map[String, String] = {
val user = userRepository.find(username)
val boss = userRepository.get(user.supervisorId)
Map(
"fullName" -> s"${user.firstName} ${user.lastName}",
"email" -> s"${user.email}",
"boss" -> s"${boss.firstName} ${boss.lastName}"
)
}
}
trait UserRepositoryComponentImpl extends UserRepositoryComponent {
def userRepository = new UserRepositoryImpl
class UserRepositoryImpl extends UserRepository {
def get(id: Int) = {
???
}
def find(username: String) = {
???
}
}
}
object UserInfoImpl extends
UserInfo with
UserRepositoryComponentImpl
}
它编译得很好。
1) 为什么博客里的代码这么复杂?
2) 这是使用蛋糕图案的惯用方式吗?
3) 为什么在这个例子中需要 Users
class?
4) 蛋糕图案应该是这样的吗(看起来没必要Users
class?
5) 还是简化版就好了?
乍一看它可能看起来很复杂,但一旦您熟悉了该模式,它就会……千篇一律且繁琐。对于您的每项服务,您都必须创建一个附带的组件来包装该服务。因此,在提供的示例中,您有一个被
UserRepositoryComponent
包裹的UserRepository
。这只是抽象,因此您需要对组件和服务都有具体的实现(即UserRepositoryComponentImpl
包装UserRepositoryImpl
)。到目前为止,您只有一项服务可能会在您的模块中使用,想象一下创建数十项服务所付出的努力 ;)是的,这是使用该模式的惯用方式。然而,该模式还有其他变体,例如
thin cake pattern
或parfait
(Dick Wall 创造的术语)你问的是
User
,但你的代码简化是删除Users
,所以我将描述它们。User
是一个简单的案例 class,应该使该示例更 accessible/easier 易于掌握。Users
然而这里没有必要(它只是另一个中间抽象级别),在我看来它们给示例带来了一些不必要的干扰。我会说你的简化版本准确地显示了蛋糕图案应该是什么样子。你有一个抽象
UserRepository
包裹在UserRepositoryComponent
中,你有这两个特征的具体实现,并且你有一些服务 (UserInfo
) 需要用户的存储库(这是 "injected" using self-type annotation).已回答。