2016-06-20 20 views
0

私の質問はScala Cake Pattern and Dependency Collisionsと非常によく似ています。しかし、私はDaniel Cの答えに示唆されているような具体的な解決策を見つけるのに苦労しています。Scala Cake Pattern:依存関係の衝突を避けるには?

ProductDetailsPage(特性)がそれぞれProductServiceModuleWsSessionModuleWsによって実装二つの独立したサービスモジュールProductServiceModuleSessionModuleが、必要です。

だからここで問題です。

どちらのモジュールもRestServiceConfigurationProviderに依存しています。

RestServiceConfigurationProviderの場合、具体的な実装はDefaultRestServiceConfigurationProvider(atm)しかありません。

一方DefaultRestServiceConfigurationProviderProductServiceModuleWs、要するにHybrisEndpointProvider又はProductServiceEndpointProvider

こととSessionModuleWsリモートRESTful Webサービスに接続するかRestEndpointProviderに依存します。特定のサービスの正確なIPアドレスは、RestEndpointProviderの実装によって提供されます。

ここで、衝突が発生します。下のコードを試してみてください。依存関係の衝突が発生する面倒なところは、コメントでマークされています。当然

ので、コンパイラはRestEndpointProviderの相反する2つの実装を訴え、すなわちHybrisEndpointProviderProductServiceEndpointProvider

ダニエルはどのような衝突を避けるために、彼の答えで述べたように、私は、別途ProductServiceModuleWsSessionModuleWsを配線しなければなりません私が捕まってしまったところ、おそらくそう

 new ProductServiceModuleWs 
     with DefaultRestServiceConfigurationProvider 
     with ProductServiceEndpointProvider 


     new SessionModuleWs 
     with DefaultRestServiceConfigurationProvider 
     with HybrisEndpointProvider 

しかし、ここのような独自の具体的なRestEndpointProvider実装とそれぞれが、あります。

これらの2つの個別に構成されたモジュールは、どのようにしてProductDetailsPageに注入され、依存性の衝突を回避することができますか?

次のコード例があります。コードは自己完結型であり、IDEで実行する必要があります。

case class RestEndpoint(url: String, username: Option[String] = None, password: Option[String] = None) 


trait RestEndpointKey { 
    def configurationKey: String 
} 

case object HybrisEndpointKey extends RestEndpointKey { val configurationKey = "rest.endpoint.hybris" } 
case object ProductServiceEndpointKey extends RestEndpointKey { val configurationKey = "rest.endpoint.productservice" } 


trait ProductDetailsPage { 
    self: ProductServiceModule with SessionModule => 
} 



trait ProductServiceModule {} 

trait SessionModule {} 


trait ProductServiceModuleWs extends ProductServiceModule { 
    self: RestServiceConfigurationProvider => 
} 


trait SessionModuleWs extends SessionModule { 
    self: RestServiceConfigurationProvider => 
} 


trait RestServiceConfigurationProvider {} 

trait DefaultRestServiceConfigurationProvider extends RestServiceConfigurationProvider { 
    self: RestEndpointProvider => 
} 


sealed trait RestEndpointProvider { 
    def endpointKey: RestEndpointKey 
} 

trait HybrisEndpointProvider extends RestEndpointProvider { 
    val endpointKey = HybrisEndpointKey 
} 

trait ProductServiceEndpointProvider extends RestEndpointProvider { 
    val endpointKey = ProductServiceEndpointKey 
} 


object Example extends App { 

    new ProductDetailsPage 
     with ProductServiceModuleWs 
     with SessionModuleWs 
     with DefaultRestServiceConfigurationProvider 
     with HybrisEndpointProvider 
     with ProductServiceEndpointProvider /// collision, since HybrisEndpointProvider already defined the endpointKey !!!!! 
    } 
} 

答えて

2

暗黙のスコープを使用すると、値をどこから取得するかを制御できます。

どこかで、名前が用語かタイプかにかかわらず、aとbの間で名前を選択します。

タイプによって区別する場合は、タイプ別に尋ねることができます。

便利なのは、Config[Value1]の設定をインストールすることができます。これは、そうでない場合は、例のようにカスタムメンバーと組み合わされます。

示されているように、語彙スコープにインプリシットを導入することもできます。

package conflict 

case class Value(s: String) 

trait Value1 extends Value 
object Value1 { 
    implicit val v: Config[Value1] = new Config[Value1] { def value = new Value("hi") with Value1 } 
} 
trait Value2 extends Value 
object Value2 { 
    implicit val v: Config[Value2] = new Config[Value2] { def value = new Value("bye") with Value2 } 
} 

trait Config[A <: Value] { def value: A } 

trait Configurator { 
    def config[A <: Value : Config]: Config[A] = implicitly[Config[A]] 
} 

trait Consumer1 { _: Configurator => 
    def f = config[Value1].value 
} 
trait Consumer2 { _: Configurator => 
    def g = config[Value2].value 
} 
trait Consumer3 { _: Configurator => 
    def h[V <: Value : Config] = config[V].value 
} 

object Test extends App with Configurator with Consumer1 with Consumer2 with Consumer3 { 
    Console println s"Using $f" 
    Console println s"Using $g" 
    locally { 
    implicit val `my local config` = new Config[Value2] { def value = new Value("hello again") with Value2 } 
    Console println s"Using ${h[Value2]}" 
    } 
} 
+0

私はあなたの例から多くを学んだ、ありがとう。 – simou

関連する問題