まず最初に、 をUserServiceComponent
の実装から分離する必要がありUserService
ます。
trait UserService extends RepositoryDelegator[User] {
def getPublicProfile(id: String): Either[Error, User]
}
trait UserServiceComponent {
val userService: UserService
}
trait DefaultUserServiceComponent extends UserServiceComponent { self: UserRepositoryComponent =>
protected class DefaultUserService extends UserService {
def getPublicProfile(id: String): Either[Error, User] = userRepository.getPublicProfile(id)
}
val userService: UserService = new DefaultUserService
}
trait AlternativeUserServiceComponent extends UserServiceComponent {
protected class AlternativeUserService extends UserService {
def getPublicProfile(id: String): Either[Error, User] = call webservice here for exemple...
}
val userService: UserService = new AlternativeUserService
}
それが冗長に見える場合は、そうです。ケーキのパターンは特に簡潔ではありません。
UserRepositoryComponent
しかし、実際には必要でない場合 ( のみを使用する場合など) に依存するという問題がどのように解決されるかに注目してくださいAlternativeUserService
。
ここで、アプリケーションをインスタンス化するときに行う必要があるのは、 または のいずれDefaultUserServiceComponent
かを混合することだけAlternativeUserServiceComponent
です。
両方の実装にアクセスする必要がある場合は、実際に 2 つの userService 値の名前を公開する必要があります。実際には、次のような 3 つの名前があります。
DefaultUserService
実装 のための defaultUserService
AlternativeUserService
実装 のための alternativeUserService
- 任意の実装の mainUserService
UserService
(アプリケーションは「混合時間」でどれを選択するか)。
例:
trait UserService extends RepositoryDelegator[User] {
def getPublicProfile(id: String): Either[Error, User]
}
trait MainUserServiceComponent {
val mainUserService: UserService
}
trait DefaultUserServiceComponent { self: UserRepositoryComponent =>
protected class DefaultUserService extends UserService {
def getPublicProfile(id: String): Either[Error, User] = userRepository.getPublicProfile(id)
}
val defaultUserService: UserService = new DefaultUserService
}
trait AlternativeUserServiceComponent {
protected class AlternativeUserService extends UserService {
def getPublicProfile(id: String): Either[Error, User] = ??? // call webservice here for exemple...
}
val alternativeUserService: UserService = new AlternativeUserService
}
次に、次のようにケーキをインスタンス化できます。
object MyApp
extends MainUserServiceComponent
with DefaultUserServiceComponent
with AlternativeUserServiceComponent
with MyUserRepositoryComponent // Replace with your real UserRepositoryComponent here
{
//val userService = defaultUserService
val mainUserService = alternativeUserService
}
上記の例では、明示的に にアクセスする必要があるサービスはコンポーネントの依存関係として配置され ( および についてDefaultUserService
も同様)、一部だけが必要なサービスは代わりに依存関係として配置されます。「混合時間」で、どのサービスが指すかを決定します (ここでは、実装を指します。DefaultUserServiceComponent
AlternativeUserService
AlternativeUserServiceComponent
UserService
MainUserServiceComponent
mainUserService
DefaultUserService