2011-04-15 8 views
6

Dejado allí unas pocas clases separadas DAO OrderDAO, ProductDAO y CustomerDAO que almacenan/recuperar los datos en la base de datos y compartir una única instancia DataSource (la fábrica de conexiones de base de datos).Pregunta sobre el patrón de la torta

Para crear una instancia de DataSource y enchufarla en DAOs, solemos utilizar Spring DI. Ahora me gustaría hacer eso en Scala sin ningún marco DI.

He leído sobre el cake pattern, y parece que yo debería hacer lo siguiente:

trait DatabaseContext { val dataSource:Datasource } 

trait OrderDAO {this:DatabaseContext => 
    ... // use dataSource of DatabaseContext 
} 

trait ProductDAO {this:DatabaseContext => 
    ... // use dataSource of DatabaseContext 
} 

object DAOImpl extends OrderDAO with ProductDAO with DatabaseContext { 
    val dataSource = ... // init the data source 
} 

¿Debo entender el patrón de la torta correctamente?

¿Puedo implementar estos DAOs de manera diferente con el patrón de tortas?

¿Qué proporciona que marcos DI como Spring no lo son?

¿Cómo puedo crear separadas OrderDAOImpl y ProductDAOImpl objetos que comparten el mismo DataSource ejemplo, en lugar de uno grande DAOImpl?

+0

Leí brevemente sobre el patrón de pastel y no vi lo que la emoción era sobre cualquiera de los dos. Parece mucho más complicado que los contenedores DI existentes. – Kevin

+0

Si te gusta o no, no es realmente relevante para la pregunta. Y "me estoy perdiendo algo" es una pregunta muy débil. Tal vez sería mejor preguntar "¿qué proporciona esto que X no ofrece?", Lo cual es una pregunta clara. –

+0

@Daniel. Gracias. He reformulado la pregunta. – Michael

Respuesta

2

Tal vez:

  • estáticamente comprueba en tiempo de compilación.
5

Las ventajas del modelo de la torta son:

  • diferencia de las soluciones DI basado en configuración en archivos, búsqueda de contratos a implementaciones se realiza en tiempo de compilación, lo que reduce y compatibilidad problemas para encontrar su clase. Sin embargo, muchos motores DI tienen una función de configuración en código alternativa
  • No se utilizan las bibliotecas de otros fabricantes . Las anotaciones de auto-tipo que le permiten usar el patrón son una característica de idioma nativo . Sin sintaxis especial se utiliza para recuperar el ejecución del contrato
  • olvido para especificar una implementación para un componente que necesitan los otros resultados de los componentes en un error de ejecución - sólo comprobar este artículo http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html y tratar de no especificar una de las componentes o la especificación de un rasgo en lugar de una clase concreta en cualquiera de los modelo de la torta ejemplos o incluso olvidar inicializar un val correspondiente a un componente necesario

Sin embargo, para experimentar estas ventajas, es necesario que se adhieran más estrictamente a la arquitectura del patrón: verifique el mismo artículo y observe los rasgos de envoltura que contienen los contratos e implementaciones reales.

Sus ejemplos no parecen ser estrictamente el patrón de tortas. En su caso, podría haber utilizado la herencia para crear implementaciones para sus rasgos y usar clases separadas para cada componente DAO. En el patrón de torta, el código de consumo sería un componente como el código DAO, y el código que ensambla las dependencias sería independiente de él.

Para ilustrar el patrón de tortas, debería agregar clases de consumo (capa de dominio o capa de IU) a su ejemplo. O en el caso de que sus componentes DAO accedieran a las características de cada uno, usted podría ilustrar el patrón de tortas solo en su DAO.

Para ser breves,

trait OrderDAOComponent { 
    val dao: OrderDAO 
    trait OrderDAO { 
     def create: Order 
     def delete(id: Int): Unit 
     //etc 
    } 
} 

trait OrderDAOComponentImpl extends OrderDAOComponent { 
    class OrderDAOJDBCImpl extends OrderDAO { 
     def create: Order = {/*JDBC-related code here*/} 
     def delete(id: Int) {/*JDBC-related code here*/} 
     //etc 
    } 
} 

//This one has a dependency 
trait OrderWebUIComponentImpl { 
    this: OrderDAOComponent => 
    class OrderWebUI { 
     def ajaxDelete(request:HttpRequest) = { 
      val id = request.params("id").toInt 
      try { 
       dao.delete(id) 
       200 
      } 
      catch { 
       case _ => 500 
      } 

     } 
    } 
} 

//This matches contracts to implementations 

object ComponentRegistry extends 
    OrderDAOComponentImpl with 
    OrderWebUIComponentImpl 
{ 
    val dao = new OrderDAOJDBCImpl 
    val ui = new OrderWebUI 
} 

//from some front-end code 
val status = ComponentRegistry.ui.ajaxDelete(request) 

Más en su ejemplo. Creo que podría ser más como pastel si:

trait DatabaseContext { val dataSource:Datasource } 

trait OrderDAOComponent {this:DatabaseContext => 
    trait OrderDAOImpl { 
     ... // use dataSource of DatabaseContext 
    } 
} 

trait ProductDAOComponent {this:DatabaseContext => 
    trait ProductDAOImpl { 
     ... // use dataSource of DatabaseContext 
    } 
} 

object Registry extends OrderDAOComponent with ProductDAOComponent with DatabaseContextImpl { 
    val dataSource = new DatasourceImpl //if Datasource is a custom trait, otherwise wrapping needed 
    val orderDAO = new OrderDAOImpl 
    val productDAO = new ProductDAOImpl 
} 

//now you may use them separately 
Registry.orderDAO.//