Use una capa de servicio con MVC


12

Si un controlador se engorda demasiado y la creación de instancias del modelo comienza a acumularse, se podría usar una capa de servicio.

  • Si acabo de ajustar la lógica dentro de una clase de servicio, obtendré un montón de servicios con uno / dos métodos. Esto se siente como un olor a código. ¿Alguna mejor práctica con respecto a esto?

  • ¿Puede un servicio instanciar modelos?

  • Si un servicio crea instancias de modelos, los servicios no se pueden probar en la unidad. ¿Solo pueden ser cubiertos por pruebas de integración?

Respuestas:


24

En 'SÓLIDO', la 'I' significa segregación de interfaz. La idea de este principio es dividir las interfaces grandes en otras más pequeñas, más modulares. En el servicio MVC normalmente tendría una interfaz en la que confiaría el controlador. No desea que sus controladores sepan sobre la implementación concreta de ese servicio. Por lo tanto, es bueno tener un montón de servicios con uno o dos métodos.

Los servicios normalmente devuelven DTO en aplicaciones grandes o modelos de dominio directamente en aplicaciones más pequeñas. Los DTO normalmente significan más trabajo, pero una mejor separación de las preocupaciones. El flujo típico es:

  • El controlador llama al servicio
  • El servicio devuelve un objeto (ya sea un DTO, modelo de dominio u otra cosa)
  • El controlador asigna el modelo DTO / dominio a un modelo de vista

El mapeo se puede hacer manualmente, pero la mayoría de los desarrolladores prefieren usar el marco de mapeo automático como Automapper porque no nos gusta escribir código de plomería y podemos ser bastante vagos :-)

http://en.wikipedia.org/wiki/Interface_segregation_principle

https://github.com/AutoMapper/AutoMapper

Una de las muchas discusiones sobre stackoverflow con respecto al uso de DTO y modelos de dominio: /programming/2680071/dto-or-domain-model-object-in-the-view-layer


1
Tendría cuidado al usar un mapeador automático aquí uglybugger.org/software/post/…
Daniel Little

AutoMapper viene con una funcionalidad de prueba de unidad incorporada que le permite verificar todas sus rutinas de mapeo con una sola línea. El autor de esta publicación no mencionó eso.
CodeART

Pero él lo sabe y lo ha usado. Los comentarios entran un poco en esto.
Daniel Little

2
Muchas clases con solo uno o dos métodos generalmente significan que no son coherentes. Una capa de servicio, si existe, debe ser delgada con la mayor parte de la lógica en los modelos. Parece bastante inútil vincular una vista a un objeto tonto que no es más que una bolsa de propiedades. El modelo en MVC debe ser el modelo de dominio rico, no anémico martinfowler.com/bliki/AnemicDomainModel.html
Andy

3

En MVC, el Modelo, no es solo un DTO o un conjunto de Gerentes / Servicios, está destinado a representar los conceptos que su aplicación está modelando. Puede pensar en esto como todo el dominio o la lógica empresarial, incluidos el estado y los comportamientos. Ahora dado que sabemos que el propósito del controlador se vuelve un poco más claro. Su trabajo es simplemente traducir comandos al Modelo y el resultado nuevamente a las vistas. Esto generalmente se realiza en forma de ViewModels que son diferentes pero a menudo se confunden con el Modelo en MVC.

Si no tiene un Modelo bien definido, es posible que haya llegado al punto en que la mayor parte de esa lógica ahora reside en los Controladores. En este punto, para comenzar a reducir el tamaño de sus controladores, puede comenzar a recuperar esta lógica en el administrador o en los objetos de servicio. Estos servicios generalmente regresan y operan en objetos DTO / Entity. Luego, el controlador se convierte en la capa de mapeo entre estos servicios y los Modelos de vista. Para algunos buenos consejos sobre mapeo, eche un vistazo a este artículo. Los amigos no permiten que sus amigos usen AutoMapper .

En cuanto a sus preguntas, la primera depende mucho de sus aplicaciones. Tendrá que refactorizar en el camino, lo que debería ser más evidente una vez que haya eliminado la lógica de sus controladores. En cuanto a las pruebas, no hay problema en crear instancias de modelos dentro de los servicios; sin embargo, si encuentra que las pruebas son difíciles, probablemente sea solo una señal de que necesita dividir el servicio en partes más pequeñas, cada una con una sola responsabilidad.


3

Los controladores solo deben contener llamadas al modelo (donde ocurre la lógica de negocios) y, en función de esas llamadas, asignar datos para la vista (objetos de información o mensajes de error), por lo tanto, los controladores serán bastante pequeños incluso para una página muy compleja, si el controlador aún se vuelve muy grande, deberías pensar que tal vez esa página debería expandirse en más páginas.

Aún así, el modelo puede ser bastante grande ... la solución que encontré fue tener una variable dentro del controlador que indica qué modelo cargar y para tareas específicas cargo el modelo específico.

Intenta obedecer el modelo de modelo-vista-controlador limpio así:

  • ver: muestra datos
  • controlador: recopila la entrada del usuario, solicita al modelo los datos solicitados y los envía de vuelta a la vista
  • modelo: interactúa con la base de datos y realiza acciones lógicas para preparar la información

-1

Considero que los servicios son realmente útiles para realizar la lógica que puede necesitar realizar más de un controlador o que simplemente no es lo suficientemente específica como para ser parte del controlador, además del hecho de que impide que mis controladores sean demasiado grandes y difíciles de leer. .

Personalmente no estoy de acuerdo con 'aaa' cuando dice que "modelo (donde ocurre la lógica de negocios)" ya que esa es la razón por la que tiene controladores, en mi opinión, los modelos deben ser simples extractores de datos para que el controlador pueda realizar la tarea necesaria; de nuevo, los servicios no deberían involucrarse en la tarea de abstracción de datos ...

solo digo yo ...


1
Si su modelo es solo un dto, ha caído en el modelo de dominio anémico antipatrón martinfowler.com/bliki/AnemicDomainModel.html
Andy
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.