2013-05-13 8 views
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は両方AddMul特性で定義されているが、その値は異なる可能性があります。私はその形質の名前に接頭辞を付けることができましたが、私はそれが醜くて脆い(def mulConstant: T)ことがわかります。それを行う良い方法はありますか?

答えて

7

よく知られているように、伝統的なケーキパターンは、通常、操作をグループ化するために、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 = ... 
} 

これはあなたの特定の名前空間の問題ではなく( 『サービス』の定義の)名前の衝突を解決しますが、残ります伝統的なケーキパターンの問題。 Daniel Spiewakのblog postがありますが、これを一般的にどのように解決できるのかを実演していますが、ソリューションには独自の(巨大な)トレードオフがあります(this talk参照)。

少し助けてくれることを願っています。

P.S.型パラメータの代わりにここで抽象型を使用するほうが良いかもしれません。

+0

あなたの答えをありがとう、それは私の問題を確かに解決します。あなたのPSに関しては、抽象タイプ 'T'を各特性に定義すると(名前は"コンポーネント "レベルで定義されるはずです)、名前型の衝突が発生します。私が間違っている ? – paradigmatic

+0

この例では、 'T'はすべての特性において同じ「もの」を意味するので、衝突しません。たとえ各形質が異なるタイプの境界を持つTに寄与しても、それらは衝突しないであろう。それらのタイプ境界は、一緒に混合されると、異なる形質からむしろ一緒に集められる。彼らが縛っている限り、衝突しないで、物事は良いです(コンパイラ用)。 Daniel Spiewakがそのブログ記事で示していることの1つです。それにもかかわらず、私は個人的に2つの異なるコンポーネントで同じものを意味するわけではないので、「コンポーネント」レベルの抽象型に「T」よりもわかりやすい名前を付けます。 –

+0

OK。しかし、ここで私は型が統一されていることを確認する必要があるので( 'T = Int'はどこでも)、全ての特性が同じ' T'を持つ依存関係を表現する必要があります。ジェネリック型以外の方法を実現する方法はありません。 – paradigmatic

0

これは少し言ってもおかしなことかもしれませんが、あなたの質問に直接答えはありませんが、単にコンストラクタへの依存性注入を行う方が簡単ですか?各共同編集者は独自の名前空間を持っているので、決して衝突はありません。クラスのパブリックAPIにも問題はありません。しかし、DIとケーキのパターンを混在させることは難しいです。

関連する問題