4

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.

oym
  • 6,983
  • 16
  • 62
  • 88

2 Answers2

3

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.

dk14
  • 22,206
  • 4
  • 51
  • 88
0

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?

tobym
  • 1,354
  • 1
  • 10
  • 11
  • Because the instantiation is always the same except for the mixed in traits. I figured it would be less code duplication to do it in one place (for the sake of this example assume that the insntantiation of the class is messy; e.g. takes in many parameters) – oym Feb 04 '15 at 23:46
  • Also, your answer is effectively the same as creating multiple factory methods, which I was hoping to avoid. – oym Feb 04 '15 at 23:48
  • @oym: It seems the only way you could do this is with a macro – Kim Stebel Feb 05 '15 at 00:10
  • I see. On more reflection, its probably cleanest (most clear to others) to just have several of these factories methods; one for each combination of mixed in traits. – oym Feb 05 '15 at 00:28
  • 1
    just to mention dirty ways: http://stackoverflow.com/questions/3254232/dynamic-mixin-in-scala-is-it-possible http://stackoverflow.com/questions/10373318/mixing-in-a-trait-dynamically – dk14 Feb 05 '15 at 00:52