2012-04-20 8 views
5

私は、アプリケーションに2つの依存関係、いくつかのpubサブシステムへの接続、およびデータベースへの接続があると言います。私はその後、私はスカラケーキのパターン - 私はケーキの複数の層を持つことができますか?

trait Functionality { this:DB with PubSub => 
    def doSomething() { 
     val key = lookup("get key") 
     subscribe(key, data => println(data)) 
    } 
} 

ように私のロジックを記述することができ、その後、私のアプリは

object Awesome extends App { 

    object repository extends Functionality with DB with PubSub { 
     def lookup(query:String) = "some key" 
     def subscribe(key:String, callback:String => Any) { 
      scala.concurrent.ops.spawn { while(true) { callback(key) ; Thread.Sleep(1000) } } 
     } 
    } 
    repository.doSomething() 
} 

ようにすることができ、全世界でも良いです

trait DB { 
    def lookup(query:String):String 
} 

trait PubSub { 
    def subscribe(key:String, callback:String => Any) 
} 

ような何かを行うことができます。

しかし、同じアプリケーションで同じデータベース実装を共有する2つのパブサブシステムに接続したいのですが?

私はケーキの第二の層にあるオブジェクトは(暗黙的に?)親レベルからDBの実装に読ま

object Awesome2 extends App { 
    object repository extends DB { 
     def lookup(query: String): String = "some other key" 

     object connection1 extends Functionality with PubSub with DB { 
      def subscribe(key: String, callback: (String) => Any) { 
       scala.concurrent.ops.spawn { while(true) { callback(key.toUpperCase) ; Thread.sleep(1000) } } 
      } 
     } 

     object connection2 extends Functionality with PubSub with DB { 
      def subscribe(key: String, callback: (String) => Any) { 
       scala.concurrent.ops.spawn { while(true) { callback(key.toLowerCase) ; Thread.sleep(1000) } } 
      } 
     } 
    } 
} 

のような何かをしたいです。私は、次の操作を実行した場合

しかし、Scalaのコンパイラは私に

error: object creation impossible, since method lookup in trait DB of type (query:String) String is not defined 
object connection2 extends Functionality with PubSub with DB { 

を伝え、それは私が

object Awesome3 extends App { 
    object repository extends DB { 
     override def lookup(query: String): String = "some other key" 

     object connection1 extends Functionality with PubSub with DB { 
      def subscribe(key: String, callback: (String) => Any) { 
       scala.concurrent.ops.spawn { while(true) { callback(key.toUpperCase) ; Thread.sleep(1000) } } 
      } 

      def lookup(query: String): String = repository.lookup(query) 
     } 

     object connection2 extends Functionality with PubSub with DB { 
      def subscribe(key: String, callback: (String) => Any) { 
       scala.concurrent.ops.spawn { while(true) { callback(key.toLowerCase) ; Thread.sleep(1000) } } 
      } 

      def lookup(query: String): String = repository.lookup(query) 
     } 
    } 
    repository.connection1.doSomething() 
    repository.connection2.doSomething() 
} 

何をしたいんが、これは私がこの形質を追加することができます厄介

の一種であります

trait DB_Base extends DB { 

    private val db:DB = this 

    trait DB_Layer extends DB { 
     def lookup(query:String):String = db.lookup(query) 
    } 
} 

その後、次の作品

object Awesome4 extends App { 
    object repository extends DB_Base { 
     override def lookup(query: String): String = "some other key" 

     object connection1 extends Functionality with PubSub with DB_Layer { 
      def subscribe(key: String, callback: (String) => Any) { 
       scala.concurrent.ops.spawn { while(true) { callback(key.toUpperCase) ; Thread.sleep(1000) } } 
      } 
     } 

     object connection2 extends Functionality with PubSub with DB_Layer { 
      def subscribe(key: String, callback: (String) => Any) { 
       scala.concurrent.ops.spawn { while(true) { callback(key.toLowerCase) ; Thread.sleep(1000) } } 
      } 
     } 
    }  
    repository.connection1.doSomething() 
    repository.connection2.doSomething() 
} 

今私は2つの層があります。どのように私は3つを得るのですか?私はプロットを失っているように感じる。

+2

ケーキはカロリーが高く、血糖負荷が高いです...そして層状ケーキの成分のリストを見たことがありますか?シンプルで自然な食べ物を好みます。つまり、せいぜい1層のケーキを用意し、それ以外の場合は必要なリソースを指定するためにdefを使用します(これはコメントです。実際には問題の解決策ではなく、 ) 'dbbase =>'を追加して 'dbbase =>'を追加し、 'DB_Layer'を落として' def dbLayer = dbbase'を追加するか、そうでなければ、明示的かつコンパクトな代替案が得られます。 –

+0

ありがとうrex。私はあなたのコメントで混乱しています。まず、 '{dbbase =>'は何をしますか?私はその構文に精通していません。第二に、結果は「素晴らしい3」のようにひどく見えませんか? – dvmlls

+0

@RexKerrは正しいですが、追加のレイヤーなしで自分のCake DIを(どのようにOPがやっているように見えるのか)見ることはできません。たとえば、DAOケーキを焼きたいとしましょう。 DAOを実装するには、データベース接続(プロダクション、ステージ、テスト)、接続タイプ(JNDI、JDBC)、DAOコントラクト自体を処理する必要があります。 OPが提示するものでわかるように、パターンが複雑になって頭が傷ついてしまいます;-)再び、ウサギの穴に落とさずにScalaのCake DIをどうやって行うことができないか – virtualeyes

答えて

4

コメントはそれを説明するのに十分な大きさではないので、基本的には「それはしないでください!代替案を示唆している。

重要な問題は、いくつかの機能のコピーを複数作成することですが、名前で名前を参照する方法はありません(タイプのみ)。解決策は次のとおりです。名前を付けます。

ダブルケーキのパターンを取ってみましょう。

trait Foo { def foo(s: String): String } 
trait Bar { def bar(s: String, f: String => Any): Any } 
trait Bippy { this: Foo with Bar => 
    def bip(s: String) = bar(foo(s),println) 
} 

さて、偉大な、我々はFoo with Barを実装して何にもBippyに混在させることができると我々はbipにできるようになります。しかし、FooBarが異なるレベルで実装されるとどうなりますか?代わりにご使用の場合

trait Bippy { 
    def myFoo: Foo 
    def myBar: Bar 
    def bip(s: String) = myBar.bar(myFoo.foo(s), println) 
} 

これは最初はもっと厄介です。しかしそれは今、ますます厄介な方法でケーキを余儀なくされるのではなく、ミックスしてマッチさせることができます。例:

object Foozle extends Foo { theFoo => 
    def foo(s: String) = s.toUpperCase 
    trait BippyImpl extends Bippy { this: Bar => 
    def myFoo = theFoo 
    def myBar = this 
    } 
    object Woozle1 extends BippyImpl with Bar { 
    def bar(s: String, f: String => Any) = f(s) 
    } 
    object Woozle2 extends BippyImpl with Bar { 
    def bar(s: String, f: String => Any) = f(s.reverse) 
    } 
} 

これで、どこからでもあらゆる機能を組み合わせることができます。唯一の欠点は、名前を付ける必要があることです。(ここでは、Woozleの共通部分を分割するために、ネストされた特性のBippyImplを作成しましたが、直接作成することもできます)。

また、元のメソッド名を混在させることはありません。プロキシを書くかメンバー変数を参照する必要があります。

それはケーキパターンの素晴らしい面のいくつかを逃してしまいますが、私の経験では、ケーキ層の大規模な混乱よりもはっきりしています。そして今、あなたはあなたが好きなだけ深く巣を掛け、必要な場所にあなたが望む細部を記入できることが分かります。

+0

私はスカラケーキの別の層がユニティーの子コンテナと同じものではないという事実に言及することに問題があります。それは私の負担です。説明する時間をとってくれてありがとう、レックス。感謝します。 – dvmlls

関連する問題