私の知る限りでは、従来のケーキ パターンには、通常、操作をグループ化するために、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
}
}
次に、"...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 = ...
}
これにより、特定の名前空間の問題が解決されますが、(「サービス」定義の) 名前の衝突は従来のケーキ パターンの問題のままです。Daniel Spiewakによるブログ投稿で、一般的にどのように解決できるかを示していますが、解決策には独自の (巨大な) トレードオフが伴います (この講演を参照)。
それが少し役立ったことを願っています。
PS ここでは型パラメーターの代わりに抽象型を使用する方が良いかもしれません