scala - 蛋糕图案——为什么这么复杂

标签 scala cake-pattern

我正在尝试了解蛋糕图案。

我正在阅读 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这个例子中需要的类?

4) 蛋糕图案应该是这样的吗(看似不必要的 Users 类?

5)还是简化版就好了?

最佳答案

  • 起初它可能看起来很复杂,但一旦你熟悉了这种模式,它就只是......样板和繁琐。对于您的每项服务,您都必须创建一个随附的组件来包装该服务。因此,在提供的示例中,您有一个 UserRepositoryUserRepositoryComponent 包裹.这只是抽象,因此您需要对组件和服务都有一个具体的实现(即 UserRepositoryComponentImpl 包装 UserRepositoryImpl )。到目前为止,您的模块中只有一个服务可以使用,想象一下创建数十个服务的努力;)
  • 是的,这是使用该模式的惯用方式。但是,该模式还有其他变体,例如thin cake patternparfait (Dick Wall 创造的术语)
  • 您在询问 User ,但您的代码简化是删除 Users ,所以我将描述它们。 User是一个简单的案例类,应该使该示例更易于访问/更易于掌握。 Users然而这里没有必要(它只是另一个中间抽象级别),并且在我看来它们给示例带来了一些不必要的噪音。
  • 我会说你的简化版本准确地显示了蛋糕图案应该是什么样子。你有一个摘要 UserRepository包裹在 UserRepositoryComponent 内,您有这两个特征的具体实现,并且您有一些需要用户存储库的服务( UserInfo )(使用自类型注释“注入(inject)”)。
  • 已经回答了。
  • 关于scala - 蛋糕图案——为什么这么复杂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41519947/

    相关文章:

    class - 为什么可以在类型字段中混入类?

    scala - Scala 的 transient 集合?

    具有不同生命周期的对象的 Scala 蛋糕模式

    scala - 避免名称与 Cake Pattern 冲突

    scala - 蛋糕图案 : How to share an instance?

    scala - Wordspec "should" "when" "in"

    scala - 作曲 Actor

    scala - Scala 中的访问器和修改器方法是什么?

    scala - 蛋糕图案 : how to get all objects of type UserService provided by components

    scala - 以蛋糕模式抽象数据库客户端