2012-04-20 12 views
6

this articleで提案されているように、一部のソフトウェアシステムの一部をコンポーネントに分割して完全にモジュール化するために、Cake Patternを使用したいと思います。最も単純なケースでは、私はいくつかのモック可能なコンポーネントを持っていたいと思います。ロギング、コンフィグ、データベース、スクリプトなどは、お互いを潜在的に使用する可能性があります。コードは、データベースおよび設定のコンポーネント(SomeConfigSomeDatabase形質が)プラグイン可能であり、これまで必要に応じて他のいくつかの実装に変更することができます。ここスカラケーキパターン:大きなコンポーネントを別々のファイルに分割する

trait AbstractConfig { 
    def config: AbstractConfigInterface 
    trait AbstractConfigInterface { 
    def test: Unit 
    } 
} 

trait SomeConfig extends AbstractConfig { 
    this: Core => 
    def config = SomeConfigImplementation 
    object SomeConfigImplementation extends AbstractConfigInterface { 
    def test = println("conf.test method called") 
    } 
} 

trait AbstractDatabase { 
    def database: AbstractDatabaseInterface 
    trait AbstractDatabaseInterface { 
    def connect: Unit 
    } 
} 

trait SomeDatabase extends AbstractDatabase { 
    this: Core => 
    def database = SomeDatabaseImplementation 
    object SomeDatabaseImplementation extends AbstractDatabaseInterface { 
    def connect = { 
     println("connect method called") 
     core.conf.test 
    } 
    } 
} 

trait Core { 
    this: AbstractDatabase with AbstractConfig => 
    def core = CoreInterface 
    object CoreInterface { 
    def db = database 
    def conf = config 
    } 
} 

object app extends Core with SomeDatabase with SomeConfig 

object Run { 
    def main(args: Array[String]) = { 
    app.core.db.connect 
    } 
} 

のように見えるかもしれません。これらの実装では、データベースと設定の両方を保持するcoreオブジェクトにアクセスできるため、データベースは必要に応じて設定にアクセスすることができ、逆も同様です。

SomeDatabaseのような特性が大きくなり、1つのファイルに収まらない場合、それを別のクラスに分割してcoreオブジェクトへのアクセスを保持する方法はありますか?具体的には、のは、私は別のファイルにSomeDatabaseにconnectメソッドのうちのいくつかのコードを移動する必要がありましょう:

// SomeDatabase.scala 
trait SomeDatabase extends AbstractDatabase { 
    this: Core => 
    def database = SomeDatabaseImplementation 
    object SomeDatabaseImplementation extends AbstractDatabaseInterface { 
    def connect = { 
     val obj = new SomeClass() 
    } 
    } 
} 

// SomeClass.scala in the same package 
class SomeClass { 
    core.conf.test // Does not compile - how to make it work?? 
} 

SomeClassはどのようSomeDatabase作品の実装の詳細ですので、私は明らかにそれ作るのが好きではないでしょうそれをアプリケーションに組み込みます。 SomeClasscoreオブジェクトへのアクセスを提供する方法はありますか?


いくつかの関連リンク:

  1. Dependency Injection vs Cake Pattern by Jan Machacek
  2. Real World Scala: Dependency Injection by Jonas Boner
  3. Dependency Injection in Scala: Extending the Cake Pattern by Adam Warsky
  4. Scalable Component Abstractions by Martin Odersky & Matthias Zenger

答えて

2

だろう最も簡単な方法コンストラクタパラメータとしてCoreSomeClassに渡す必要があります。

// SomeDatabase.scala 
trait SomeDatabase extends AbstractDatabase { 
    this: Core => 
    def database = SomeDatabaseImplementation 
    object SomeDatabaseImplementation extends AbstractDatabaseInterface { 
    def connect = { 
     val obj = new SomeClass(SomeDatabase.this) // pass it here 
    } 
    } 
} 

// SomeClass.scala in the same package 
class SomeClass(coreComp: Core) { // use it here 
    coreComp.core.conf.test 
} 

興味深いことに、私は本当にただCoreInterfaceまたはAbstractConfigInterfaceを渡したいが、彼らは、内側の型であるという事実は、本当に難しいと判断します。

+0

デイブ、答えに感謝します。これまでのところ合理的な唯一の方法と思われます。私がそれについて掘り下げない唯一のことは、コアメソッドを呼び出すたびに 'coreComp.'をタイプする必要があることです。残念ながら、 'CoreInterface'を直接使用するオプションはないようですね。 – nab

+1

'coreComp._'をインポートすると、入力を減らすことができます。 – leedm777

関連する問題