Como nos 2 últimos posts eu falei sobre dúvidas que eu tinha recebido, vou continuar na mesma linha, só que agora busquei a dúvida nesta thread do grupo .NetArchitects, entre outras (muitas) coisas que foram discutidas foi levantado a dúvida sobre a responsabilidade da View, na dúvida o Emmanuel propõe um cenário que está exposto abaixo:
Se você tem que exibir transações de conta corrente, por exemplo, débito e crédito, mas quando o saldo fica negativo você quer colocar a linha em vermelho, é uma regra de apresentação. Mas onde estaria esse código? Acho que não estaria no domínio por que não diz respeito a ele… Seria no Controller?
Esta é uma pergunta mais comum do que se imagina, já me perguntaram diversas vezes sobre a responsabilidade de cada letra do MVC, e é por isso que eu coloquei como título deste post como “Cada um no seu quadrado”.
A resposta simples e direta para a pergunta acima é que essa regra fica na View, mas vamos elaborar um pouco mais, por que não no Controller? Simples, por que assim ele estaria invadindo o quadrado da View, vou exemplificar o meu ponto de vista:
No cenário proposto pelo Emmanuel, o Controller enviaria os dados através da ViewData para a View e ela por sua vez verificaria se o Saldo é negativo, caso fosse exibiria ele em vermelho, vamos ver um pouco de código.
Vamos começar pelo modelo, para representar o cenário criei 3 classes, a Conta que contem os dados da conta e as transações, a Transação que representa cada transação da conta e o Repositório que para o exemplo irá preencher os objetos com dados randômicos.
Conta
public class Conta { public int Numero { get; set; } public int Agencia { get; set; } public IList<Transacao> Transacoes { get; set; } public double Saldo { get; set; } }
Transação
public class Transacao { public DateTime Data { get; set; } public string Descricao { get; set; } public double Valor { get; set; } }
Repositório
public class ContaRepositorio { public Conta get(int Agencia, int Numero) { //aqui faria a consulta no banco, vou fazer um //faz de conta para facilitar Conta conta = new Conta(); conta.Agencia = Agencia; conta.Numero = Numero; conta.Transacoes = new List<Transacao>(); Random rnd = new Random(); for (int i = 0; i < 15; i++) { conta.Transacoes.Add(new Transacao{Data = DateTime.Now.AddDays(-i),Descricao = "Transação nº "+i, Valor= rnd.Next(0,358)}); } conta.Saldo = rnd.Next(-1245, 1245); return conta; } }
Vamos ver agora o Controller, criei uma única action que mandará através da ViewData os dados da Conta, neste ponto é que surge a dúvida, posso colocar a inteligência de trocar a cor aqui? Bom, tecnicamente pode, poderia criar um objeto intermediário que tem sido chamado de ViewModel para armazenar esta “condição”, mas na minha opinião o Controller estará invadindo o quadrado da View. Na soluçao proposta abaixo eu passo somente os dados para a View.
Controller
public class ContaController : Controller { // // GET: /Conta/ public ActionResult Index() { ContaRepositorio rep = new ContaRepositorio(); ViewData.Model = rep.get(1234, 123456); return View(); } }
Vamos agora para a View, de acordo com o valor do saldo é escolhido a classe que será aplicano na tag que contém o saldo.
View
<h2>Extato de Conta</h2> <fieldset> <p>Numero: <%= Html.Encode(Model.Numero) %></p> <p>Agencia: <%= Html.Encode(Model.Agencia) %></p> <table> <thead> <tr> <th>Data</th> <th>Descrição</th> <th>Valor</th> </tr> </thead> <tbody> <%foreach (var item in Model.Transacoes){%> <tr> <td><%= Html.Encode(String.Format("{0:d/M/yyyy}", item.Data))%></td> <td><%= Html.Encode( item.Descricao)%></td> <td><%= Html.Encode(String.Format("{0:F}", item.Valor)) %></td> </tr> <%} %> </tbody> </table> <% string classe; if (Model.Saldo < 0) { classe = "negativo"; } else { classe = "positivo"; } %> <p>Saldo: <span class="<%=classe%>"><%= Html.Encode(String.Format("{0:F}", Model.Saldo)) %></span></p> </fieldset>
No CSS adicionei as seguintes classes:
.positivo{color:Blue;} .negativo{color:Red;}
O resultado esta na imagem abaixo:
Este código eu fiz com a intenção de demonstrar que a View não é burra (no bom sentido), ela pode e deve conter regras que são de interface, como no exemplo acima.
O Emmanuel quis complicar um pouco mais o cenário e colocou o seguinte:
E se esse núcleo do meu sistema é consumido por diversas interfaces? Mobile, desktop, web; essa regra da interface, não deveria estar em outro local que não a interface?
Quando tive os primeiros contatos com o ASP.NET MVC tive a mesma dúvida, mas com o tempo e várias pesquisas fiquei convencido que isto não é possível e nem interessante, digo isso por 2 motivos:
- O primeiro é técnico, como o MVC é um padrão de Interface Gráfica ele depende muito do ambiente, que neste caso é o ASP.NET MVC, ou seja, eu não conseguiria reutilizar o Controller do ASP.NET MVC para uma aplicação Windows Form ou uma aplicação Mobile.
- O segundo é sobre os diferente tipos de mídias que poderíamos utilizar para a nossa interface, cada uma dessas mídias tem suas próprias preocupações de acessibilidade e usabilidade e para lidar com essas preocupações cada uma delas deve ter autonomia.
O código deste exemplo já está disponível.
Bom, espero ter respondido a dúvida do Emmanuel e de outras pessoas. Até a próxima.
Victor Cavalcante
Victor Cavalcante é marido da Mariana Frioli, pai do Eduardo, Microsoft MVP, trabalha com desenvolvimento web a 11 anos e é focado em padrões de desenvolvimento para web. Trabalha na Lambda3 (www.lambda3.com.br), empresa ágil que insiste em fazer software certo. É ainda professor universitário e atua no grupo .NET Architects desde seu início. Acompanhe seu twitter para saber as novidades:@vcavalcante.