6

ケーキの型紙について勉強中です。

私はそれについてこのブログを読んでいます。

そのブログのコード例は次のとおりです。

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) それとも簡易版でいいの?

4

1 に答える 1

9
  1. 最初は複雑に見えるかもしれませんが、そのパターンに慣れると、定型的で扱いにくいものになります。あなたのサービスごとに、そのサービスをラップする付随するコンポーネントを作成する必要があります。したがって、提供された例では、UserRepositoryによってラップされた がありUserRepositoryComponentます。そして、これは単なる抽象化であるため、コンポーネントとサービスの両方に具体的な実装 (つまり、UserRepositoryComponentImplラッピングUserRepositoryImpl) が必要です。これまでのところ、モジュールで使用できるサービスは 1 つしかありません。何十ものサービスを作成する努力を想像してみてください ;)

  2. はい、これはそのパターンを使用する慣用的な方法です。ただし、そのパターンの他のバリエーションもあります。たとえばthin cake pattern、またはparfait(Dick Wall によって造られた用語)。

  3. あなたは について尋ねてUserいますが、コードの単純化は を削除するUsersことだったので、両方について説明します。Userその例をよりアクセスしやすく/把握しやすくする単純なケースクラスです。Usersただし、ここでは不要でした (これは別の中間レベルの抽象化です)。私の意見では、これらは例に不必要なノイズをもたらします。

  4. 単純化されたバージョンは、ケーキのパターンがどのように見えるかを正確に示していると思います。UserRepositoryの内部にラップされた抽象がUserRepositoryComponentあり、これらの両方の特性の具体的な実装がありUserInfo、ユーザーのリポジトリを必要とするサービス ( ) があります (自己型注釈を使用して「注入」されます)。

  5. すでに回答済み。

于 2017-01-07T13:07:03.377 に答える