par*_*tic 6 scala traits name-clash cake-pattern
我目前正在使用Cake Pattern来实现一些优化算法.我经常遇到名字碰撞问题.例如:
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
}
Run Code Online (Sandbox Code Playgroud)
这里,constant在两者Add和Mul特征中都有定义,但它们的值可能不同.我可以在名称前加上特征名称,但我发现它很丑陋(def mulConstant: T).有没有更好的方法呢?
小智 7
据我所知,传统的蛋糕模式通常涉及1层特性嵌套,以便将操作组合在一起.然后,外层声明实际的"服务"(这里:添加,Mul,操作)而不定义它.
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
}
}
Run Code Online (Sandbox Code Playgroud)
然后,当将"... Component"特征混合在一起时,依赖关系是有线的:
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 = ...
}
Run Code Online (Sandbox Code Playgroud)
这解决了您的特定命名空间问题,但名称冲突("服务"定义)仍然是传统蛋糕模式的问题.Daniel Spiewak 发表了一篇博客文章,演示了如何解决这一问题,但解决方案有其自身的一套(巨大的)权衡(参见本演讲).
希望有所帮助.
PS而不是类型参数在这里使用抽象类型可能更好