Reputation: 7083
I have (for lack of a better term) a factory method that encapsulates constructing an object:
def createMyObject = new SomeClass(a, b, c, d)
Now, depending on the context, I will need to mix in one or more traits into SomeClass:
new SomeClass with Mixin1
or
new SomeClass with Mixin2 with Mixin3
Instead of creating multiple separate factory methods for each "type" of instantiation, how can I pass in the traits to be mixed in so that it can be done with a single method? Or perhaps there is a good pattern for this that is structured differently?
I'd like to maintain the encapsulation so I'd rather not have each consumer just create the class on its own.
Upvotes: 4
Views: 1612
Reputation: 22374
If you need only mixins without method overriding, you can just use type classes:
trait Marker
class C[+T <: Marker] { def b = 1 }
trait Marker1 extends Marker
implicit class I1[T <: Marker1](c: C[T]) {def a = 6 + c.b}
trait Marker2 extends Marker
implicit class I2[T <: Marker2](c: C[T]) {def a = 5 + c.b}
trait Marker3 extends Marker
implicit class I3[T <: Marker3](c: C[T]) {def k = 100}
trait Marker4 extends Marker3
implicit class I4[T <: Marker4](c: C[T]) {def z = c.k + 100} //marker3's `k` is visible here
scala> def create[T <: Marker] = new C[T]
create: [T <: Marker]=> C[T]
scala> val o = create[Marker1 with Marker3]
o: C[Marker1 with Marker3] = C@51607207
scala> o.a
res56: Int = 7
scala> o.k
res57: Int = 100
scala> create[Marker4].z
res85: Int = 200
But it won't work for create[Marker1 with Marker2].a
(ambiguous implicits), so no linearization here. But if you want to just mix-in some methods (like in javascript's prototypes) and maybe inject something - seems to be fine. You can also combine it with traditional linearized mix-in by adding some traits to C, I1, I2, etc.
Upvotes: 3
Reputation: 1344
You can instantiate the class differently depending on the context.
def createMyObject =
if (context.foo)
new SomeClass
else
new SomeClass with Mixin1
However, if the consumers are the ones that know the traits that are supposed to be mixed in, then why wouldn't you just instantiate things there?
Upvotes: 0