I'd like to use the Cake Pattern for splitting parts of some software system into components to make it completely modular as proposed in this article. In the simplest case I'd like to have some mockable components, let's say Logging, Config, Database, Scripts etc which could potentially use each other. The code might look like
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
}
}
Here the database and config components (SomeConfig
and SomeDatabase
traits) are pluggable and can be changed to some other implementations if ever needed. Their implementations have access to core
object which holds both database and config, so the database can access config if needed and vice versa.
So the question is: If ever some trait like SomeDatabase
becomes large and doesn't fit into a single file how to split it into separate classes retaining access to the core
object? To be more specific, let's say I need to move some code out of connect method in SomeDatabase
to another 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
is implementation details of how SomeDatabase works, so I obviously wouldn't like to make it a trait and mix it in to application. Is there any way to provide access to core
object for SomeClass
?
Some related links:
coreComp.
in each invocation of any core method. Unfortunately there doesn't seem to be an option to work withCoreInterface
directly, does it? – Farnsworth