2

バックグラウンド

Scala アプリケーション内で暗黙的なオブジェクトをスコープに入れるためのベスト プラクティスを理解しようとしています。

私は Playframework 2.2.0 (Scala 2.10) Web アプリを持っており、Authorization のトレイトを混ぜています。チェックします。Authenticated オブジェクトは、スコープ内に user_id があることを確認し、ユーザー情報、アクセス トークン、および MagicNotebook と呼ばれるデータ パッケージ オブジェクトをキャッシュ、データベース、および Web サービス呼び出しから取得しようとします。リクエストが有効な場合、さまざまなオブジェクトがラップされたリクエストに追加されます。

  object Authenticated extends ActionBuilder[AuthenticatedRequest] {
    def invokeBlock[A](request: Request[A],
                       block: (AuthenticatedRequest[A] => Future[SimpleResult])) = {
      request.session.get(userName).map { implicit userId =>
        Cache.getAs[DbUser](userKey).map { user =>
          Cache.getAs[String](accessTokenKey).map { accessToken =>
            Cache.getAs[MagicNotebook](magicNotebookKey(userId)).map { notebook =>
              block(AuthenticatedRequest(user, accessToken, notebook, request) )
            }.getOrElse(startOver)
          }.getOrElse {
            requestNewAccessToken(user.token).flatMap { response =>
              persistAccessToken(response).map { accessToken =>
                Cache.getAs[MagicNotebook](magicNotebookKey(userId)).map { notebook =>
                  block(AuthenticatedRequest(user, accessToken, notebook, request))
                }.getOrElse(startOver)
              }.getOrElse(startOver)
            }
          }
        }.getOrElse(startOver) // user not found in Cache
      }.getOrElse(startOver) // userName not found in session
    }
  }
}

case class AuthenticatedRequest[A](user: DbUser,
                                   accessToken: String,
                                   magic: MagicNotebook,
                                   request: Request[A])
    extends WrappedRequest[A](request)

質問

これらの暗黙の変数をスコープに入れる最良の方法は何ですか?

暗黙のクラスを通して?

次のコードで、暗黙的なコンパニオン クラスを使用しようとしました。

object Helper {
  implicit class Magical(request: AuthenticatedRequest[AnyContent]) {
    def folderMap = request.magic.fMap
    def documentMap = request.magic.dMap
  }
}

ただし、この方法で暗黙の利点を実際に得ることはできません。

def testing = Authenticated { implicit request =>
  import services.Helper._
  request.magic.home.folders // doesn't compile
  request.magic.home.folders(Magical(request).ffMap) // compiles, but not implicitly
  Ok("testing 123")
}

インポートステートメントを介して?

私が考えた 1 つの可能性は、コントローラー内の import ステートメントを使用することでした。MagicNotebookここでは、暗黙の変数として使用したいスコープ内のオブジェクトがリクエストに含まれています。

def testing = Authenticated { implicit request =>
  import request.magic._
  request.magic.home.folders // implicit map is a parameter to the `folder` method
  Ok("testing 123")
}

仲間の特性を通して?

ここでは、コントローラーのスコープへAuthenticateのオブジェクトの 2 つのマップを含む特性に混合されるコンパニオン 特性を作成します。MagicNotebook

trait Magic {
  implicit def folderMap[A](implicit request: AuthenticatedRequest[A]) =
    request.magic.fMap
  implicit def docMap[A](implicit request: AuthenticatedRequest[A]) = 
    request.magic.dMap
}

私の好みはコンパニオン トレイト ソリューションですが、見落としていたより良い方法があるのではないかと考えていました。MagicNotebookオブジェクト全体の代わりに の 2 つのマップを暗黙的なパラメーターとして使用するために、暗黙的な変数を使用するメソッドを書き直すことになりました。

しかし、もっと良い方法はないかと改めて考えました。

4

2 に答える 2