2012-04-20 9 views
6

Me gustaría utilizar el patrón Cake para dividir partes de algún sistema de software en componentes para hacerlo completamente modular como se propone en this article. En el caso más simple, me gustaría tener algunos componentes ficticios, digamos Logging, Config, Database, Scripts, etc., que potencialmente podrían usarse entre sí. El código podría ser comoScala Cake Pattern: división de componentes grandes en archivos separados

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

Aquí las bases de datos y configuración de componentes (SomeConfigSomeDatabase y rasgos) son enchufable y se puede cambiar a algunas otras implementaciones si alguna vez es necesario. Sus implementaciones tienen acceso al objeto core que contiene bases de datos y configuraciones, por lo que la base de datos puede acceder a la configuración si es necesario y viceversa.

Así que la pregunta es: ¿Alguna vez, algún rasgo como SomeDatabase se vuelve grande y no cabe en un solo archivo cómo dividirlo en clases separadas conservando el acceso al objeto core? Para ser más específico, digamos que necesito mover algo de código de método connect en SomeDatabase a otro archivo:

// 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 es detalles de implementación de cómo SomeDatabase obras, por lo que, obviamente, no les gustaría que sea una rasgo y mezclarlo en la aplicación. ¿Hay alguna manera de proporcionar acceso al objeto core para SomeClass?


Algunos enlaces relacionados:

  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

Respuesta

2

Lo más sencillo que hacer sería pasar Core en como parámetro de constructor al 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 
} 

Curiosamente, realmente sólo quería pasar CoreInterface o AbstractConfigInterface, pero el hecho de que son tipos interiores realmente hizo tan difícil.

+0

Dave, gracias por la respuesta. Hasta ahora, parece ser la única forma razonable. Lo único que no me interesa es la necesidad de escribir 'coreComp' en cada invocación de cualquier método central. Lamentablemente, no parece haber una opción para trabajar directamente con 'CoreInterface', ¿o sí? – nab

+1

Puede 'importar coreComp._' para reducir el tipeo. – leedm777

Cuestiones relacionadas