Scala 避免名称与蛋糕模式冲突

Scala 避免名称与蛋糕模式冲突,scala,traits,cake-pattern,name-clash,Scala,Traits,Cake Pattern,Name Clash,我目前正在使用蛋糕模式来实现一些优化算法。我经常碰到名字冲突的问题。例如: 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 de

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

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
Add
Mul
特征中都有定义,但它们的值可能不同。我可以用trait名称作为名称的前缀,但我发现它既丑陋又脆弱(
def mulConstant:T
)。有更好的方法吗?

据我所知,传统的蛋糕模式通常包括1层特征嵌套,将操作分组在一起。然后,外层声明实际的“服务”(这里是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 = ...
}
这解决了特定的名称空间问题,但名称冲突(服务定义)仍然是传统cake模式的问题。丹尼尔·斯皮瓦克(Daniel Spiewak)的一篇文章展示了如何在总体上解决这个问题,但这个解决方案有自己的一套(巨大的)权衡(参见)

希望这有点帮助


另外,在这里使用抽象类型可能比使用类型参数更好,这可能有点不合时宜,也不是对您问题的直接回答,但简单地将依赖项注入构造函数不是更容易吗?每个协作者都有自己的名称空间,因此不会发生冲突。类的公共api也没有问题。但是,仍然很难混合DI和蛋糕模式。

谢谢你的回答,它确实解决了我的问题。关于你的PS,如果我在每个特征中定义抽象类型
T
,我也会有名称类型冲突(因为它应该在“组件”级别定义)。我错了吗?在这个特殊的例子中,
T
在所有特征中都表示相同的“东西”,所以它们不会冲突。即使每个特征贡献了一个T,但它们不会发生冲突,当它们混合在一起时,它们的类型边界相当于从不同的特征收集在一起。只要它们的边界不冲突,一切都很好(对于编译器)。这是Daniel Spiewak在那篇博文中展示的一件事。然而,我个人会给“组件”级别的抽象类型一个比
T
更具描述性的名称,因为2
T
s在两个不同的组件中并不一定意味着相同的东西。好的。但是这里我需要确保类型是统一的(
typet=Int
无处不在),所以我需要表达所有混合的特征都具有相同的
T
的依赖性。除了泛型类型,我看不出如何实现这一点。嗯,也许这一要点可以澄清一点?此外,使用类型类而不是继承可能更好地表达这个特定问题。例如,参见Scala的
Numeric
typeclass或Spire()。