2010-09-06 6 views
17

Como he estado usando Grails cada vez más, me encuentro escribiendo código en varios controladores que realmente parece que debería ser parte de una clase de dominio. A veces, este código de dominio contiene una llamada a una clase de servicio. Por ejemplo, hace poco escribí un método de dominio que parecía algo como esto:¿Es malo llamar a los servicios de Grails desde objetos de dominio?

class Purchase { 

    // Injected 
    def paymentService 

    String captureTransactionId 
    Boolean captured 

    // ... 

    def capture() { 
     captureTransactionId = paymentService.capturePurchase(this) 
     captured = captureTransactionId != null 
    } 

no me siento la escritura de plano sucio este código, pero no he hecho un estudio de las mejores prácticas de diseño en Grails, por lo que quería obtener algunas opiniones

+0

Un último comentario: ¿cuándo se inyectan los servicios? Por ejemplo, si carga 10,000 Compras desde una base de datos, ¿se inyectará el PaymentService en ellas? El rendimiento sufrirá significativamente. – wishihadabettername

+0

@ User277434 - Hibernate en realidad no está destinado a hacer este tipo de carga por lotes. Si tuviera tantos registros para cargar de una vez, podría omitir el uso de hibernación, o usar una consulta con una proyección para evitar la creación del objeto. –

Respuesta

15

Voy y vuelvo con cosas como esta. Antes de Grails no tuve problemas con clases de dominio anémicas y poner todo en ayudantes. La gran razón por la que a menudo terminaba con clases anémicas es la validación. Es simple validar la capacidad de anulación, la longitud, etc. dentro de la clase, pero la singularidad requiere una verificación de la base de datos y no es relevante para una clase de dominio (en una aplicación que no sea de Grails), así que pasaría eso a un ayudante. Ahora tengo la validación en dos lugares, así que consolidaría en el helper y me quedaría con una clase solo de datos.

Pero Grails reemplaza la necesidad de DAO al cablear en métodos GORM en clases de dominio, y también reemplaza la necesidad de validadores al poner la validación en las clases de dominio. Esto crea problemas a la hora de decidir qué lógica de negocio debe ir en la clase de dominio y qué debería ser en un servicio u otro ayudante: los servicios constituyen un excelente lugar para colocar la lógica de negocios que podría ser necesaria en un validador o método de clase de dominio.

Sí, no es OO-puro, sí crea un ciclo (el servicio llama a la clase de dominio y la clase de dominio llama al servicio), no, no es "el camino de primavera", pero muchos de Grails no camino".

Este tipo de acoplamiento hace más difícil separar una aplicación en componentes o complementos para su reutilización, pero declarar servicios con 'def paymentService' ayuda mucho ya que no está acoplado a un nombre de paquete o implementación.

+0

Sí, he estado usando los servicios principalmente como componentes pequeños y enfocados que hablan con sistemas externos y luego los llamo desde cualquier lugar que tenga sentido. Creo que están desacoplados por el modelo de inyección que mencionaste. Me gusta mucho más que el tipo de modelo de Script de Transacción que @duffymo y @ammoQ parecen sugerir. –

+0

Usted dice que esto no es "el camino de primavera", pero esta es una presentación del fundador de Spring en la que defiende hacer exactamente esto: http://www.infoq.com/presentations/rod-johnson-are-we-herehere- sin embargo, –

+0

Yo recomendaría hacerlo de la forma que sea más rápida y sencilla de implementar, que en este caso es usar el servicio dentro de la clase de dominio. Hacerlo bien se ve bien en un libro, pero, sinceramente, ¿con qué frecuencia vas a utilizar tus clases de dominio para una aplicación diferente utilizando la misma base de datos? Incluso si se convierte en un requisito más adelante, resuelva el problema, no ahora. –

3

No creo que las clases de dominio/modelo sean servicios de llamadas. Debería ser al revés.

Un servicio puede orquestar otros servicios para cumplir con un caso de uso. Creo que ese es el camino correcto a seguir.

+1

¿Puede explicar la razón de ser de su opinión? ¿Qué hace que sea mejor o peor hacerlo de una manera que de otra? –

+0

Estoy de acuerdo con duffymo; la razón es el principio de la menor sorpresa. Una clase de dominio que llama a una clase de servicio es sorprendente y una fuerte señal de que las responsabilidades no se han asignado correctamente a las clases. –

+0

Esa es la forma Spring, y Spring es la base de Grails. – duffymo

3

Solo doy mi opinión personal. Dado que Grails admite la inyección automática de servicios en clases de dominio (a diferencia de inyectar servicios en clases de Groovy estándar, que debe configurar usted mismo), supongo que fue diseñado para ser utilizado de esa manera y, por lo tanto, no es una mala práctica.

También hace que el código sea más legible con algo como "myDomainInstance.someUsefulMethod()", que "someService.someUsefulMethod (myDomainInstance)" (espero que sepas a qué me refiero).

+0

Sí, sé a qué te refieres, y yo siento lo mismo. Encuentro esto similar al uso de una interfaz segregada en Java y que tu código de dominio llame a clases DAO. Ese patrón parece haber inspirado cosas como GORM donde simplemente le dices a la clase de dominio que se salve. Veo esto como lo mismo. Le digo a la clase de pago que se capture y habla con el sistema externo para que se ocupe de ello. De esta forma, el acoplamiento es bajo y evité escribir una clase de servicio de * estilo de secuencia de comandos muy * de procedimiento. –

0

No estoy seguro de si es correcto o incorrecto.

En casos como el ejemplo, ¿qué tal ir de un lado a otro: poner el código paymentService.capturePurchase() dentro de la clase Purchase o poner toda la lógica en el servicio?

+0

Porque quiero separar las preocupaciones y mantener una sola responsabilidad para mis componentes. Quiero que el código de dominio actualice la lógica del dominio y quiero que el código de servicio interactúe con el sistema de pago externo. –

Cuestiones relacionadas