Use uma camada de serviço com MVC


12

Se um controlador ficar muito gordo e a instanciação do modelo começar a aumentar, uma camada de serviço poderá ser usada.

  • Se eu apenas quebrar a lógica dentro de uma classe de serviço, receberei vários serviços com um / dois métodos. Parece um cheiro de código. Alguma prática recomendada a respeito disso?

  • Um serviço pode instanciar modelos?

  • Se um serviço instancia modelos, os serviços não podem ser testados em unidade. Eles só podem ser cobertos por testes de integração?

Respostas:


23

No 'SOLID', o 'I' significa Segregação de Interface. A idéia geral desse princípio é dividir grandes interfaces em menores, mais modulares. No serviço MVC, normalmente, havia uma interface na qual o controlador confiava. Você não deseja que seus controladores saibam sobre a implementação concreta desse serviço. Portanto, é bom ter vários serviços com um ou dois métodos.

Os serviços normalmente retornam DTOs em aplicativos grandes ou modelos de domínio diretamente em aplicativos menores. DTOs normalmente significam mais trabalho, mas melhor separação de preocupações. O fluxo típico é:

  • O controlador chama o serviço
  • Serviço retorna um objeto (seja um DTO, modelo de domínio ou outra coisa)
  • O controlador mapeia o modelo de DTO / domínio para um modelo de visualização

O mapeamento pode ser feito manualmente, mas a maioria dos desenvolvedores prefere usar a estrutura de mapeamento automático, como o Automapper, porque não gostamos de escrever código de encanamento e podemos ser bastante preguiçosos :-)

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

https://github.com/AutoMapper/AutoMapper

Uma das muitas discussões sobre o stackoverflow em relação ao uso de DTOs e modelos de domínio: /programming/2680071/dto-or-domain-model-object-in-the-view-layer


1
Gostaria de ter cuidado usando um mapeador de auto aqui uglybugger.org/software/post/...
Daniel Little

O AutoMapper vem com uma funcionalidade de teste de unidade integrada que permite verificar todas as suas rotinas de mapeamento com uma linha. O autor deste post não mencionou isso.
CodeART

Mas ele sabe disso e o usou. Os comentários entram nisso um pouco.
Daniel Little

2
Muitas classes com apenas um ou dois métodos geralmente significam que não são coesas. Uma camada de serviço, se existir, deve ser fina, com a maior parte da lógica nos modelos. Parece um pouco inútil vincular uma visão a um objeto idiota que nada mais é do que uma sacola de propriedade. O modelo no MVC deve ser o modelo de domínio rico, não um anêmico um martinfowler.com/bliki/AnemicDomainModel.html
Andy

3

Os controladores devem conter apenas chamadas para o modelo (onde a lógica de negócios acontece) e, com base nessas chamadas, atribuir dados para a exibição (objetos de informações ou mensagens de erro), portanto, os controladores serão muito pequenos, mesmo para uma página muito complexa, se o controlador ainda fica muito grande, você deve pensar que talvez essa página deva ser expandida em mais páginas.

Ainda assim, o modelo pode ser bastante grande ... a solução que encontrei foi ter uma variável dentro do controlador que informa qual modelo carregar e para tarefas específicas carrego o modelo específico.

Tente obedecer ao modelo model-view-controller como este:

  • view: exibe dados
  • controller: coleta a entrada do usuário, solicita ao modelo os dados solicitados e os envia de volta à visualização
  • modelo: interage com o banco de dados e executa ações lógicas para preparar informações

2

No MVC, o Modelo, não é apenas um DTO ou um conjunto de Gerentes / Serviços, ele representa os conceitos que seu aplicativo está modelando. Você pode pensar nisso como o domínio inteiro ou a lógica de negócios, incluindo estado e comportamentos. Agora, já que sabemos que o objetivo do controlador se torna um pouco mais claro. Seu trabalho é simplesmente converter comandos no modelo e o resultado de volta nas visualizações. Isso geralmente é feito na forma de ViewModels que são diferentes, mas geralmente confundidos com o modelo no MVC.

Se você não possui um Modelo bem definido, pode ter chegado ao ponto em que a maior parte dessa lógica agora reside nos próprios Controladores. Neste ponto, para começar a reduzir o tamanho de seus controladores, você pode começar a puxar essa lógica de volta aos objetos de gerente ou serviço. Esses serviços geralmente retornam e operam em objetos como DTO / Entidade. Em seguida, o controlador se torna a camada de mapeamento entre esses serviços e os modelos de exibição. Para obter algumas boas dicas de mapeamento, dê uma olhada neste artigo. Amigos não permitem que amigos usem o AutoMapper .

Quanto às suas perguntas, a primeira depende muito de suas aplicações. Você precisará refatorar ao longo do caminho, o que deve ficar mais aparente quando você remover a lógica dos controladores. Quanto ao teste, não há problema em instanciar modelos dentro dos serviços; no entanto, se você acha difícil testar, provavelmente é apenas um sinal de que você precisa dividir o serviço em partes menores, cada uma com uma única responsabilidade.


-1

Acho serviços realmente úteis para executar lógicas que talvez precisem ser executadas por mais de um controlador ou que não sejam específicas o suficiente para fazer parte do controlador, além do fato de impedir que meus controladores fiquem grandes e difíceis de ler. .

Pessoalmente, não concordo com 'aaa' quando ele diz que "modelo (onde a lógica do negócio acontece)", já que essa é a razão de você ter controladores, na minha opinião, os modelos precisam ser simples abstratores de dados para que o controlador possa executar a tarefa necessária; novamente os serviços não devem se envolver na tarefa de abstração de dados ...

apenas dizendo yo ....


1
Se o seu modelo é apenas um dto você caiu para o modelo de domínio anêmico antipattern martinfowler.com/bliki/AnemicDomainModel.html
Andy
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.