Черты характера Scala / образец пирога против классов случая - PullRequest
2 голосов
/ 07 октября 2010

В моем веб-приложении у авторизованного пользователя есть по крайней мере 4 "аспекта": данные, относящиеся к сеансу http, постоянные данные, данные facebook, бизнес-данные времени выполнения.

Я решил использовать композицию класса дел вместочерты по крайней мере по двум причинам:

  • смешивание черт может привести к конфликтам имен
  • я хочу, чтобы такие классные плюсы, как сопоставление с образцом и метод копирования

Хотелось бы узнать мнение опытных скалистов на эту тему.Похоже, что черты и / или шаблон торта должны подходить для таких задач, но, как я уже упоминал выше, есть проблемы ... Очевидно, что я не только хочу реализовать это быстро и легко, но и глубоко понять его для использованияв будущем.

Так есть ли в моем решении какие-либо недостатки и недоразумения, или это правильно?Связанный код выглядит так:


case class FacebookUserInfo(name: String, friends: List[Long])
case class HttpUserInfo(sessionId: String, lastInteractionTime: Long, reconnect: Boolean)
case class RuntimeQuizUserInfo(recentScore: Int)
trait UserState {
  def db: User
  def http: HttpUserInfo
}

case class ConnectingUser(db: User, http: HttpUserInfo) extends UserState
case class DisconnectedUser(db: User, http: HttpUserInfo, facebook: Option[FacebookUserInfo]) extends UserState
case class AuthorizedUser(db: User, http: HttpUserInfo, facebook: FacebookUserInfo,
                          quiz: RuntimeQuizUserInfo) extends UserState

Ответы [ 2 ]

3 голосов
/ 07 октября 2010

Я думаю, что ответ прост: переходите к наследованию, если все действительно «принадлежит» вашему объекту, если все находится в одной «проблемной области».

Цель шаблона тортов состоит в том, чтобы отделить части объекта, которые так или иначе необходимы, но на самом деле не являются его частью, например, стратегия, оформление, конфигурация, контекст и т. д. В качестве примера можно привести протоколирование. Как правило, мы говорим о ситуациях, которые вы не хотите «жестко связывать», например. В некоторых случаях вы можете использовать DI-фреймворк (например, Guice или Spring) в Java. См. http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html для хорошего примера.

Вопрос, который часто помогает решить, что делать: «Как я могу проверить поведение объекта?». Если вам трудно настроить правильную среду тестирования, есть вероятность, что вам следует отделить вещи, а это означает DI, что часто может быть удобно реализовано с помощью шаблона тортов.

1 голос
/ 08 октября 2010

Третий вариант - использовать неявные преобразователи, такие как " pimp my library ", что, вероятно, не требуется, поскольку у вас есть контроль над кодом.

Все зависит от того, насколько непрозрачным (или прозрачным) вы хотите быть относительно определенного аспекта вашего объекта. Вы можете представить его простым старым классом case для остального мира, но внутренне заставить его выполнять дополнительную работу, используя импликации. Использование класса case для хранения данных является уместным, но я также чувствую, что неудобно представлять один и тот же объект, используя три класса (ConnectingUser, DisconnectedUser, AuthenticatedUser) в зависимости от ее состояния аутентификации.

Для UserState вы можете предоставить экстрактор, чтобы он вел себя как класс case:

object UserState {
  def unapply(state: UserState) = Some(state.db, state.http)
}

это можно использовать в состоянии соответствия следующим образом:

val user = ConnectingUser(User(), HttpUserInfo("foo", 0, false))
user match {
  case UserState(db, http) => println(http)
}
...