Scala作为要混合的参数传递特征

时间:2015-02-04 23:18:03

标签: scala traits

我(缺少更好的术语)封装构造对象的工厂方法:

def createMyObject = new SomeClass(a, b, c, d)

现在,根据上下文,我需要将一个或多个特征混合到SomeClass中:

new SomeClass with Mixin1

new SomeClass with Mixin2 with Mixin3

而不是为每个"类型"创建多个单独的工厂方法。实例化,我如何传入要混合的特征,以便可以用一个方法完成?或者也许有一个很好的模式,结构不同?

我想保持封装,所以我不希望每个消费者只是自己创建这个类。

2 个答案:

答案 0 :(得分:3)

如果只需要mixins而没有方法覆盖,则可以使用类型类:

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

但它不会对create[Marker1 with Marker2].a(含糊不清的含义)起作用,所以这里没有线性化。但是如果你想混合一些方法(比如javascript&#39; s原型)并且可能注入一些东西 - 似乎没问题。您还可以将它与传统的线性化混合相结合,为C,I1,I2等添加一些特性。

答案 1 :(得分:0)

您可以根据上下文不同地实例化类。

def createMyObject =
  if (context.foo)
    new SomeClass
  else
    new SomeClass with Mixin1

但是,如果消费者知道应该混入的特征,那你为什么不在那里实例化呢?