2016-05-17 20 views
21

Play! FrameworkScalaに1年近く使っています。私は現在、バージョン2.5.xを使用しています。Play Frameworkで@SingletonをScalaのオブジェクトよりも使うのはなぜですか?

私はPlayのコントローラーの進化と、開発者がどのように静的なルートobjectを離れてしまったのかを知っています。

私はまた、Guiceの使用状況を知っています。

あなたがactivatorをダウンロードして実行する場合:

activator new my-test-app play-scala 

をアクティベーターはあなたのためのテンプレートプロジェクトを生成します。 私の質問は、具体的にそのテンプレートのthisファイルです。

私のテストアプリ/アプリ/サービス/ Counter.scala

package services 

import java.util.concurrent.atomic.AtomicInteger 
import javax.inject._ 

/** 
* This trait demonstrates how to create a component that is injected 
* into a controller. The trait represents a counter that returns a 
* incremented number each time it is called. 
*/ 
trait Counter { 
    def nextCount(): Int 
} 

/** 
* This class is a concrete implementation of the [[Counter]] trait. 
* It is configured for Guice dependency injection in the [[Module]] 
* class. 
* 
* This class has a `Singleton` annotation because we need to make 
* sure we only use one counter per application. Without this 
* annotation we would get a new instance every time a [[Counter]] is 
* injected. 
*/ 
@Singleton 
class AtomicCounter extends Counter { 
    private val atomicCounter = new AtomicInteger() 
    override def nextCount(): Int = atomicCounter.getAndIncrement() 
} 

またthisファイルにその使用状況を見ることができます:

私のテストアプリ/アプリ/コントローラ/CountController.scala

package controllers 

import javax.inject._ 
import play.api._ 
import play.api.mvc._ 
import services.Counter 

/** 
* This controller demonstrates how to use dependency injection to 
* bind a component into a controller class. The class creates an 
* `Action` that shows an incrementing count to users. The [[Counter]] 
* object is injected by the Guice dependency injection system. 
*/ 
@Singleton 
class CountController @Inject() (counter: Counter) extends Controller { 

    /** 
    * Create an action that responds with the [[Counter]]'s current 
    * count. The result is plain text. This `Action` is mapped to 
    * `GET /count` requests by an entry in the `routes` config file. 
    */ 
    def count = Action { Ok(counter.nextCount().toString) } 

} 

これは、構築物を持つすべてのコントローラを意味@Inject() (counter: Counter)にはCounterの同じインスタンスが送信されます。

だから私の質問は次のとおりです。

この例のためにあなただけのScalaのオブジェクトを使用することができるときなぜ、コントローラに@Singleton、その後@Injectそれを使うのか?
コードが大幅に少なくなっています。

例:

私のテストアプリ/アプリ/サービス/ Counter.scala

package services 

trait ACounter { 
    def nextCount: Int 
} 

object Counter with ACounter { 
    private val atomicCounter = new AtomicInteger() 
    def nextCount(): Int = atomicCounter.getAndIncrement() 
} 

ので、同じようにそれを使用します。

私のテストアプリ/アプリ/コントローラ/ CountController.scala

package controllers 

import javax.inject._ 
import play.api._ 
import play.api.mvc._ 

import services.{Counter, ACounter} 

/** 
* This controller demonstrates how to use dependency injection to 
* bind a component into a controller class. The class creates an 
* `Action` that shows an incrementing count to users. The [[Counter]] 
* object is injected by the Guice dependency injection system. 
*/ 
@Singleton 
class CountController extends Controller { 
    //depend on abstractions 
    val counter: ACounter = Counter 

    def count = Action { Ok(counter.nextCount().toString) } 

} 

違いは何ですか?注射が好まれているのはなぜですか?

+2

パラメータを渡す必要がないかどうかは関係ありませんしかし、そうした場合、guiceが依存関係をインスタンス化して注入するためのクラスにする必要があります。 –

答えて

13

注射は好ましい方法ですか?一般的にはそう

依存性注入を使用してのカップルの利点:Counterの具体的な実装から

  1. デカップルコントローラ。
    • objectを使用する場合は、コントローラを変更して別の実装を指すようにする必要があります。EG Counter2.nextCount().toString
  2. あなたは
    • Counterの内側にあなたがWSコールをしていると言うことができますGuiceのカスタムバインディングを使用してテスト中の実装を変更することができます。これは単体テストを困難にする可能性があります。 Guiceとの依存関係注入を使用している場合は、CounterAtomicCounterの間のバインドを、テストのために具体的に書いたオフラインバージョンCounterに置き換えることができます。 Guice for Playテストの使用に関する詳細は、hereを参照してください。

またDIへの移行のために持っていたプレイmotivationsを参照してください。

私は、Springや他のJavaフレームワークを使って、依存性注入がひどく間違っているのを見てきたので、私は一般的に言っています。私はあなた自身の判断を使用する必要がありますが、プレーのためのDIを使用する側で間違っていると言いたいと思います。

3

私は私はあなたの質問を理解している場合、わからないけど、ための注射が好ましい:別のクラスが提供してあなたの依存関係を交換することが容易である

    アプリケーションの
  • 異なる部分が少ない
  • を結合されています同じ機能を使用する必要があります(コードをいくつか変更してオブジェクトのすべての部分を探す必要はありません)
  • (特に何かを模擬する必要がある場合)

まもなく解説:ソリッドの原則からのD:「抽象に依存する」。 Concreteに依存しないでください」

4

例えば、あなたがDAOを注入したサービスクラスを持っていて、コントローラでサービスを使いたい場合は、 (IMO)はGuiceとのDIです...また、あなたは1つの場所(モジュール)に依存関係を持つことができます。

関連する問題