2017-01-07 3 views
5

Я пытаюсь узнать о шаблоне пирога.торт - почему это так сложно

Я читаю 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) Или это упрощенная версия просто отлично?

+1

В блоге есть раздел с комментариями. почему бы вам не начать спрашивать автора? – pedrorijo91

+0

:) :) :) :) :) :) - ты смешной – jhegedus

+0

извините, не заметил, только что видел комментарий от 3 лет назад .. ** Я не много копал в коде **, но Я думаю, что это просто еще один уровень косвенности.что может помочь в тестах, если вы хотите издеваться над этим поведением – pedrorijo91

ответ

8
  1. Сначала может показаться, что это сложно, но как только вы познакомитесь с этим рисунком, это просто ... котельная и громоздкая. Для каждой вашей службы вы должны создать сопроводительный компонент, который будет обертывать эту службу. Итак, в приведенном примере у вас есть UserRepository, который завернут UserRepositoryComponent. И это только абстракция, поэтому вам нужно иметь конкретную реализацию как для компонента, так и для службы (например, UserRepositoryComponentImpl обертывание UserRepositoryImpl). И пока у вас есть только одна услуга, которая может быть использована в ваших модулях, представьте себе усилия по созданию десятков услуг;)

  2. Да, это идиоматический способ использования этого шаблона. Однако существуют и другие варианты этого шаблона, например. thin cake pattern или parfait (термин, придуманный Dick Wall)

  3. Вы спрашиваете о User, но ваш код упрощением было удалить Users, поэтому я опишу их обоих. User - это простой класс case, который должен сделать этот пример более доступным/понятным. Users, однако, здесь не было необходимости (это просто еще один промежуточный уровень абстракции), и, на мой взгляд, они привносят в пример лишний шум.

  4. Я бы сказал, что ваша упрощенная версия показывает, как выглядит торт. У вас есть реферат , завернутый в UserRepositoryComponent, у вас есть конкретная реализация обоих этих признаков, и у вас есть некоторая услуга (UserInfo), для которой требуется репозиторий пользователей (который «вводится» с помощью аннотации самонастройки).

  5. Уже ответил.

+0

Спасибо за подробное объяснение, я исправил вопросы 3 и 4, действительно, я имел в виду «Пользователи», поэтому писать «Пользователь» была опечатка, которую я сделал. – jhegedus

+1

К сожалению, я могу дать только один голос за этот подробный ответ. – ipoteka

Смежные вопросы