2012-04-20 15 views
6

Mi piacerebbe utilizzare il motivo di torta per suddividere parti di alcuni sistemi software in componenti per renderlo completamente modulare come proposto in this article. Nel caso più semplice mi piacerebbe avere alcuni componenti mockable, diciamo Logging, Config, Database, Script ecc. Che potrebbero potenzialmente usarsi l'un l'altro. Il codice potrebbe sembrarePattern di torta alla scala: divisione di componenti di grandi dimensioni in file separati

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 
    } 
} 

Qui i componenti di database e di configurazione (SomeConfig e SomeDatabase tratti) sono a innesto e può essere cambiato in alcune altre implementazioni, se mai necessario. Le loro implementazioni hanno accesso all'oggetto core che contiene sia il database che la configurazione, quindi il database può accedere alla configurazione se necessario e viceversa.

Quindi la domanda è: Se mai qualche tratto come SomeDatabase diventa grande e non si adatta in un unico file come dividere in classi separate di ritegno accesso all'oggetto core? Per essere più precisi, diciamo che ho bisogno di spostare un certo codice di metodo connect in SomeDatabase ad un altro file:

// 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 è dettagli di implementazione di come le SomeDatabase opere, quindi ovviamente non vorrebbe farne un tratto e mescolare per l'applicazione. Esiste un modo per fornire l'accesso all'oggetto core per SomeClass?


Alcuni link correlati:

  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

risposta

2

La cosa più semplice da fare sarebbe per passare Core come parametro costruttore su SomeClass.

// 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 
} 

interessante, volevo solo passare CoreInterface o AbstractConfigInterface, ma il fatto che essi sono tipi interiori fatto davvero così difficile.

+0

Dave, grazie per la risposta. Finora sembra essere l'unico modo ragionevole. L'unica cosa che non scrivo è la necessità di digitare 'coreComp' in ogni invocazione di qualsiasi metodo principale. Sfortunatamente non sembra che ci sia un'opzione per lavorare direttamente con 'CoreInterface', vero? – nab

+1

È possibile "importare coreComp._" per ridurre la digitazione. – leedm777

Problemi correlati