3

私は play 2.1 プロジェクトに取り組んでおり、scala 設計の問題に関するガイダンスが必要です。このアプリケーションでは、着信リクエストからのクライアント情報を格納するリクエスト コンテキスト オブジェクトがモデル レイヤーで必要です。

case class ClientContext(clientName: String) 

object ClientContext {
  def apply(request: Request) = {
    new ClientContext(request.params("clientName")) //pseudo code
  }
}

私のモデル

object MyDAO {
  def findAll(context: ClientContext) = { ... }
}

次に、コントローラーでモデルの dao メソッドに渡す必要があります。

object MyController extends Controller {
  def index = Action { implicit request => 
    val results = MyDAO.findAll(ClientContext(request))
    Ok(results)
  }
}

はクラスimplicit requestによって提供されますAction(私はそう思います) 。implicit request =>ClientContext(request)

Action ラッパーと暗黙的な値を使用してコードを改善する方法はありますか? context: ClientContextメソッドで暗黙的なパラメーターとして宣言しMyDAO.findAll、次の方法でアクションを記述できるようにしたいと考えています。

object MyDAO {
  def findAll(implicit context: ClientContext) = { ... }
}

def index = ActionWithContext {
  val results = MyDAO.findAll
  Ok(results)
} 

それを達成するためにActionWithContext(適用メソッドを持つメソッドまたはオブジェクト)を書くことは可能ですか?私が今持っている最も近いものは次のとおりです

def ActionWithContext(action: ClientContext => Result) = {
  Action { implicit request =>
    action(ClientContext(request))
  }
} 

利用方法

def index = ActionWithContext { context => 
  val results = MyDAO.findAll(context)
  Ok(results)
}

この設計を改善するための提案は役に立ちます。ありがとう!

PS: 正直なところ、これが Java の場合はコードをさらに単純化することは考えませんが、scala であるため、いくつかの scala パターンを学ぶ良い機会になるかもしれないと考えました。

4

2 に答える 2

3

私は暗黙を使用して似たようなものを実装しました:

私はHeader代わりに私のものと呼んでContextいますが、私たちは両方とも同じことを達成しています。

私のコントローラーはすべて、Header特性をミックスインします:

object Accounts extends AuthController with Header { ... }

私のHeader特性は次のようになります。

trait Header {
    implicit def withUserInfo(implicit maybeUser: Option[User]): UserInfo = {
        // create user info object
    }
}

次に、コントローラーのアクションを次のように記述できます。

def index = MaybeAuthenticated { implicit maybeUser => implicit request =>
    // do stuff
    val foo = new Foo()
    Ok(views.html.accounts.index(foo))
}

テンプレートには次のようなメソッド シグネチャがあります。

@(foo: Foo)(implicit userInfo: UserInfo)

MaybeAuthenticatedオプションでオブジェクトを復元する単なるアクションでありUser、play20-auth モジュールからのものです。実際、ここで 2 つの可能性を示しました。

  1. 暗黙のパラメーターを受け取る暗黙の関数にトレイトを混在させます。
  2. 次のような独自のアクション メソッドを記述します。MaybeAuthenticated

MaybeAuthenticated次のようになります。

private def maybeAuthenticated(f: Option[Account] => Request[AnyContent] => Result): Action[AnyContent] = {
    Action(BodyParsers.parse.anyContent)(req => f(restoreUser(req))(req))
}

protected def MaybeAuthenticated = maybeAuthenticated _

最初の方法の方が理解しやすいと思います。

編集:暗黙の説明については、さらに説明が必要だと思います。

implicit上記で使用されている場所を考えてみましょう。

暗黙のdef withUserInfo(暗黙の多分ユーザー: オプション[ユーザー]): ユーザー情報

に混在するオブジェクトではHeader、このメソッドはスコープ内になります。コンパイラは、aが既にスコープ内にある場合に、UserInfoオブジェクトがスコープ内にある必要がある関数を検索します。Option[User]コンパイラは、不足しているオブジェクトを提供するために暗黙的に呼び出します。withUserInfoUserInfo

私のテンプレートに必要な暗黙のUserInfoオブジェクトに注意してください。このテンプレート関数を呼び出す (Ok(...)呼び出し) とき、コンパイラは暗黙的なオブジェクトを埋める必要がありUserInfoます。これはwithUserInfo、スコープ内の implicit を呼び出して渡すことによって行われmaybeUserます。

暗黙を少し明確にすることを願っています。

于 2013-03-22T19:18:56.163 に答える
1

ライアンの提案のおかげで、ここに別の解決策があります ClientContext オブジェクトでは、適用メソッドを暗黙的なパラメーターを受け取る暗黙的な変換にもします

object ClientContext {
  implicit def apply(implicit request: Request) = {
    new ClientContext(request.params("clientName")) //pseudo code
  }
}

次に、コントローラーで次のように記述できます

def index = Action { implicit request => 
  val results = MyDAO.findAll
  Ok(results)
}

を取り除く方法があるかどうかはimplicit requestわかりませんが、これは今ではかなり簡潔です。

于 2013-03-22T22:35:27.383 に答える