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:
- Dependency Injection vs Cake Pattern by Jan Machacek
- Real World Scala: Dependency Injection by Jonas Boner
- Dependency Injection in Scala: Extending the Cake Pattern by Adam Warsky
- Scalable Component Abstractions by Martin Odersky & Matthias Zenger
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
È possibile "importare coreComp._" per ridurre la digitazione. – leedm777