简体   繁体   中英

Scala passing in traits as parameters to be mixed in

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.

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.

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?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM