How to declare anonymous mixin using a type parameter in Scala
There have been some questions asked that are somewhat related to this problem, but they don't seem to fit quite right.
I'm using the Cake pattern to slide a "Storage" system in place in production code, and a stub storage system in for testing purposes. This is all great, but there's a class that's being instantiated within the original class that also needs to have this stub storage system mixed in. Since it's hidden inside the implementation, I don't have access to it.
Things look like this:
class Main { this: Storage =>
...
val used = Used(...)
...
}
class Used { this: Storage =>
...
}
When testing "Used" I simply new Used with StubStorage
and off I go. I used to do the same with Main
but that was before it made use of Used
. Now that Main
makes a naive instantiation of Used
I've got this problem.
I wanted to try it this way:
class Main[T <: Storage] { this: T =>
...
val used = Used[T](...)
...
}
class Used[T <: Storage] { this: T =>
...
}
object Used {
def apply[T <: Storage](...) = new Used(...) with T
}
But of course that doesn't work because the compiler doesn't have enough information to discover T
. Is there a magic recipe for this? I've played around with it f开发者_如何学运维or a bit and it seems to be cumbersome enough that the standard OO injection method is actually less trouble, but I could be missing something.
I've looked at the implicit Factory concept but I can't pound that into shape to work for mixins.
EDIT: It's amazing the clarity that writing the question publicly gives. :) I haven't solved the problem the way I originally intended, but there is a simple solution to the actual problem:
trait UsedProvider {
def createUsed = Used.apply _
}
class Main { this: Storage with UsedProvider =>
val used = createUsed(...)
}
Then I would just do the following in the test: new Main with StubStorage with StubUsedProvider
.
I haven't solved your original problem either but have you considered using an abstract class for Main
and provide the value for used
where you need it?
abstract class Main { this: Storage =>
val s = "s"
val used: Used
}
Then instantiate like this:
val main = new Main with StubStorage { val used = new Used(s) with StubStorage }
精彩评论