2012-03-08 6 views
18

私はまだScala's Cake Patternを学んでいます。 「コンポーネント」の設定を一元化する利点と、それらのコンポーネント(デフォルトではオーバーライド可能)のデフォルトの実装を提供できるという利点があります。Scala Cake Patternは、ハードコードされた依存関係を奨励しますか?

しかし、依存関係を記述するために自己タイプの特性を使用することは、関心領域を混在させるようです。コンポーネントの目的は、そのコンポーネントのさまざまな実装を抽象化することです。しかし、コンポーネントに記載されている依存関係リストは、それ自体実装上の懸念事項です。例えば

、のは、私はウィジェットの完全なデータベース、私はウィジェットの特定の種類を検索することができます、レジストリ、およびウィジェットを処理するために、レジストリを使用するアルゴリズムのいくつかの並べ替えを持っているとしましょう:

case class Widget(id: Int, name:String) 

trait DatabaseComponent { 
    def database: (Int => Widget) = new DefaultDatabase() 

    class DefaultDatabase extends (Int => Widget) { 
    // silly impl 
    def apply(x: Int) = new Person(x, "Bob") 
    } 
} 

trait RegistryComponent { 
    this: DatabaseComponent => // registry depends on the database 

    def registry: (List[Int] => List[Widget]) = new DefaultRegistry() 

    class DefaultRegistry extends (List[Int] => List[Widget]) { 
    def apply(xs: List[Int]) = xs.map(database(_)) 
    } 
} 

trait AlgorithmComponent { 
    this: RegistryComponent => // algorithm depends on the registry 

    def algorithm: (() => List[Widget]) = new DefaultAlgorithm() 

    class DefaultAlgorithm extends (() => List[Widget]) { 
    // look up employee id's somehow, then feed them 
    // to the registry for lookup 
    def apply: List[Widget] = registry(List(1,2,3)) 
    } 
} 

そして今、あなたには、いくつかの中央設定にそれをまとめることができます。

object Main { 
    def main(args: Array[String]) { 
    val algorithm = new AlgorithmComponent() with RegistryComponent with DatabaseComponent 

    val widgets = println("results: " + algorithm.processor().mkString(", ")) 
    } 
} 

私は別のデータベースに変更したい場合は、私は私のミックスインを変更することで簡単に注入することができます


しかし、がデータベースを使用していない別のレジストリコンポーネントを混在させたい場合はどうすればいいですか?

RegistryComponentを別の(デフォルト以外の)実装でサブクラス化しようとすると、RegistryComponentはDatabaseComponentの依存関係を含めるように指示します。レジストリコンポーネントは、トップレベルのAlgorithmComponentに必要なものなので、RegistryComponentを使用する必要があります。

何か不足していますか?コンポーネントのいずれかで自己型を使用する瞬間、すべての可能な実装で同じ依存関係を使用する必要があると宣言しています。

他に誰かがこの問題に遭遇しましたか?それを解決するケーキのような方法は何ですか?

ありがとうございます!

+0

Daveによれば、インターフェイスが不足しているため、implsを切り離しています。ケーキパターンが欠けているものを探している場合は、EJB、Spring:トランザクション、セキュリティ、リソース設定などの問題を認識しているコンテナを見てください。ケーキのパターンはそれに対処していないので、Google Guiceのように軽いだけです。 –

答えて

17

ケーキパターンでは、少なくともexample I always go toで、コンポーネントのインターフェイス定義をデフォルト実装から分離する必要があります。これは、インターフェイスの依存関係を実装の依存関係から完全に分離します。

trait RegistryComponent { 
    // no dependencies 
    def registry: (List[Int] => List[Widget]) 
} 

trait DefaultRegistryComponent extends RegistryComponent { 
    this: DatabaseComponent => // default registry depends on the database 

    def registry: (List[Int] => List[Widget]) = new DefaultRegistry() 

    class DefaultRegistry extends (List[Int] => List[Widget]) { 
    def apply(xs: List[Int]) = xs.map(database(_)) 
    } 
} 
+5

右。自己型は他の種類の依存宣言とまったく同じです。具体的なエンティティ(悪い)や抽象的なもの(良い)への依存関係を示すことができます。唯一のやり方は、ケーキパターンが、抽象的なインターフェースとコンクリートコンポーネントの両方を特性としてエンコードしていることです。混乱する可能性があります。 –

関連する問題