私の質問はScala Cake Pattern と Dependency Collisionsに非常に似ています。しかし、ダニエル C の回答で提案されているように、具体的な解決策を見つけるのに苦労しています。
だからここに問題があります:
A ProductDetailsPage
(特性) には、2 つの独立したサービス モジュールProductServiceModule
およびが必要で、それぞれ およびSessionModule
によって実装されます。ProductServiceModuleWs
SessionModuleWs
両方のモジュールは に依存していRestServiceConfigurationProvider
ます。
このRestServiceConfigurationProvider
の場合、使用可能な具体的な実装は 1 つだけです: DefaultRestServiceConfigurationProvider
(atm)。
一方、は、どちらが aまたは aであるかDefaultRestServiceConfigurationProvider
によって異なります。RestEndpointProvider
HybrisEndpointProvider
ProductServiceEndpointProvider
つまり、リモート RESTful Web サービスに接続しますProductServiceModuleWs
。SessionModuleWs
特定のサービスの正確な IP アドレスは、RestEndpointProvider の実装によって提供されます。
さて、ここで衝突が発生します。以下のコードを試してみてください。依存関係の衝突が発生する厄介な場所はコメントでマークされています。
RestEndpointProvider
当然のことながら、コンパイラは の 2 つの競合する実装、つまりHybrisEndpointProvider
とについて不平を言います。ProductServiceEndpointProvider
ダニエルが彼の答えで述べたように、そのような衝突を避けるために、それぞれ独自の具体的な RestEndpointProvider 実装を使用して、ProductServiceModuleWs
と を別々に配線する必要があります。SessionModuleWs
new ProductServiceModuleWs
with DefaultRestServiceConfigurationProvider
with ProductServiceEndpointProvider
new SessionModuleWs
with DefaultRestServiceConfigurationProvider
with HybrisEndpointProvider
しかし、ここで行き詰まりました。
ProductDetailsPage
これらの 2 つの個別に構成されたモジュールを、依存関係の衝突を回避しながらケーキ パターンを利用しながら、どのように挿入することができるでしょうか?
これがサンプルコードです。コードは自己完結型であり、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 !!!!!
}
}