6

我目前正在使用蛋糕模式来实现一些优化算法。我经常遇到名称冲突问题。例如:

trait Add[T] { this: Foo[T] =>
  def constant: T
  def plus( t1: T, t2: T ): T
  def add( t: T ) = plus( t, constant )
}

trait Mul[T] { this: Bar[T] =>
  def constant: T
  def times( t1: T, t2: T ): T
  def mul( t: T ) = times( t, constant )
}

trait Operations[T] { this: Add[T] with Mul[T] =>
  def neg( t: T ): T
}

在这里,在和特征constant中都有定义,但它们的值可能不同。我可以在名称前加上特征名称,但我发现它又丑又脆()。有没有更好的方法呢?AddMuldef mulConstant: T

4

2 回答 2

7

据我所知,传统的蛋糕模式通常涉及一层特征嵌套,将操作组合在一起。然后,外层声明实际的“服务”(这里:Add、Mul、Operations)而不定义它。

trait AddComponent[T] { this: FooComponent[T] =>
  def addition: Add

  trait Add {
    def constant: T
    def plus( t1: T, t2: T ): T
    def add( t: T ) = plus( t, constant )
  }
}

trait MulComponent[T] { this: BarComponent[T] =>
  def multiplication: Mul

  trait Mul {
    def constant: T
    def times( t1: T, t2: T ): T
    def mul( t: T ) = times( t, constant )
  }
}

trait OperationsComponent[T] { this: Add[T] with Mul[T] =>
  def operations: Operations

  trait Operations {
    def neg( t: T ): T
  }
}

然后,当将“...组件”特征混合在一起时,依赖关系是连线的:

trait IntOperations extends Operation[Int] {
  class IntAdd extends Add { ... }
  class IntMul extends Mul { ... }
}

class MyFooBar extends FooComponent[Int] with BarComponent[Int] with IntOperations {
  lazy val addition = new IntAdd
  lazy val multiplication = new IntMul
  lazy val foo = ...
  lazy val bar = ...
}

这解决了您特定的命名空间问题,但是(“服务”定义的)名称冲突仍然是传统蛋糕模式的问题。Daniel Spiewak 发表了一篇博客文章,展示了一般如何解决该问题,但该解决方案带有自己的一组(巨大的)权衡(请参阅此演讲)。

希望能有所帮助。

PS而不是类型参数,在这里使用抽象类型可能会更好

于 2013-05-13T10:41:22.110 回答
1

说起来可能有点不合时宜,也不是直接回答你的问题,但是简单地对构造函数进行依赖注入不是更容易吗?每个协作者都有自己的命名空间,因此永远不会发生冲突。而且类的public api也没有问题。然而,仍然很难混合 DI 和蛋糕模式。

于 2013-05-14T17:09:13.870 回答