O 'C' no MVC é realmente necessário?

38

Entendo o papel do modelo e a visualização no padrão Model-View-Controller, mas tenho dificuldade em entender por que um controlador é necessário.

Vamos supor que estamos criando um programa de xadrez usando uma abordagem MVC; o estado do jogo deve ser o modelo e a GUI deve ser a visualização. O que exatamente é o controlador neste caso?

É apenas uma classe separada que possui todas as funções que serão chamadas quando você digita em um bloco? Por que não apenas executar toda a lógica do modelo na própria exibição?

Anne Nonimus
fonte
11
Pessoalmente, é isso que eu faço . Pode haver casos em que não há alternativa ao MVC, mas eu não aguento mais.
Mike Dunlavey
10
Três palavras ... "Separação de Preocupação".
Travis J
4
Quase todos os programas do Windows anteriores ao .net usavam o Doc-View sem controlador. Isso parece ter sido relativamente bem-sucedido.
Martin Beckett
Martin, monólitos incapazes.
Independente
Eu respondi abaixo, mas vou acrescentar que sim, você pode criar um aplicativo sem classes de controlador distintas, mas isso não seria o MVC. Você está assumindo "uma abordagem MVC", então sim, os controladores desempenham um papel importante. Se você escolher algum paradigma que não seja o MVC, é bem possível que você não tenha nenhum controlador.
Caleb

Respostas:

4

Usando o seu exemplo, o Controlador seria o que decidira o que era uma jogada legal ou não. O Controlador informaria à vista como organizar as peças no quadro no arranque, usando as informações recebidas do Modelo. Há mais coisas que podem ser tratadas pelo controlador, mas a chave é pensar na lógica de negócios nessa camada.

Há momentos em que tudo o que o Controlador faz é passar informações para a frente e para trás, como uma página de inscrição. Outras vezes, o Controller é a parte difícil do desenvolvimento, porque há muitas coisas que precisam ser feitas nessa camada, como impor regras ou fazer contas complicadas, por exemplo. Não esqueça o controlador!

JustinDoesWork
fonte
36
"Usando o seu exemplo, o Controlador seria o que decidia o que era uma jogada legal ou não". Este é um mau exemplo :( essa lógica também deve estar no modelo. Caso contrário, sua lógica será dividida entre o controlador e o modelo.
Dime
6
@ Dime - O modelo não deve conter lógica alguma. O controlador será o responsável pela lógica, portanto, "controlando".
Travis J
34
@TravisJ Não concordo lá. Controlar não significa saber como fazer um trabalho. É sobre controlar os objetos que o fazem. Portanto, a lógica para fazer o trabalho estaria no modelo e o controlador controlaria qual modelo usar para executar os requisitos necessários da ação, etc. Muita lógica nos controladores, na minha opinião, seria receita para a mancha do controlador ...
dreza
25
O objetivo principal da OOP é ter bits coesivos de dados e comportamento mantidos juntos e encapsulados internamente. O "modelo" modela o comportamento e os dados.
22612 Misko
12
-1 O controlador não deve conter lógica de negócios. O modelo é "o aplicativo", contém os dados e possui rotinas que podem ser chamadas para tudo o que pode acontecer no aplicativo; não necessariamente tudo em um arquivo ou classe. A vista visualiza o estado do modelo. O controlador constrói uma ponte sobre o modelo / vista e o mundo real / entrada. Deseja "publicar" o aplicativo como um aplicativo da web? Só precisa de um controlador que lide com HTTP e uma exibição baseada em HTML apropriada. Deseja uma interface de linha de comando para seu aplicativo? Só precisa de um controlador e visualização adequados. O modelo, a lógica de negócios, nunca muda nesses casos.
deceze
39

Por que não apenas executar toda a lógica do modelo na própria exibição?

O controlador é a cola que une o modelo e a visualização, e também é o isolamento que os mantém separados. O modelo não deve saber nada sobre a visualização e vice-versa (pelo menos na versão do MVC da Apple). O controlador age como um adaptador bidirecional, convertendo ações do usuário da visualização em mensagens para o modelo e configurando a visualização com dados do modelo.

O uso do controlador para separar o modelo e a visualização torna seu código mais reutilizável, mais testável e mais flexível. Considere o seu exemplo de xadrez. É claro que o modelo incluiria o estado do jogo, mas também pode conter a lógica que afeta as alterações no estado do jogo, como determinar se uma jogada é legal e decidir quando o jogo termina. A vista exibe um tabuleiro de xadrez e as peças e envia mensagens quando uma peça se move, mas não sabe nada sobre o significado por trás das peças, como cada peça se move etc. O controlador conhece tanto o modelo quanto a vista, bem como o fluxo geral do programa. Quando o usuário pressiona o botão 'novo jogo', é um controlador que diz ao modelo para criar um jogo e usa o estado do novo jogo para configurar o tabuleiro. Se o usuário fizer uma jogada,

Veja o que você obtém mantendo o modelo e visualize em separado:

  • Você pode alterar o modelo ou a vista sem alterar o outro. Pode ser necessário atualizar o controlador quando você altera um deles, mas de certa forma isso faz parte da vantagem: as partes do programa com maior probabilidade de alteração estão concentradas no controlador.

  • O modelo e a visualização podem ser reutilizados. Por exemplo, você pode usar a mesma exibição de tabuleiro de xadrez com um feed RSS como modelo para ilustrar jogos famosos. Ou você pode usar o mesmo modelo e substituir a exibição por uma interface baseada na Web.

  • É fácil escrever testes para o modelo e a exibição para garantir que eles funcionem da maneira que deveriam.

  • O modelo e a visualização geralmente podem tirar proveito das peças padrão: matrizes, mapas, conjuntos, seqüências de caracteres e outros contêineres de dados para o modelo; botões, controles, campos de texto, visualizações de imagem, tabelas e outros para a visualização.

Caleb
fonte
11
Na arquitetura MVC original para aplicativos de desktop, as visualizações eram classes ativas, observando o modelo diretamente e desconectadas do controlador.
kevin Cline
O problema com todas as respostas é que existem tantas interpretações do MVC quanto as pessoas postando. E os benefícios listados acima se aplicam apenas a uma interpretação específica do MVC. Se alguém colocar a maior parte da lógica no controlador (ou modelo) e solicitar que o View chame / inicie chamadas de método específicas no controlador, isso tornará o combo Controlador / Modelo independente e muito reutilizável. Na maioria das vezes, é necessária uma nova visão. Nunca tive a necessidade de reutilizar uma exibição. Até o seu exemplo de RSS pode ser facilmente manipulado com uma nova Visualização que usa a antiga com uma camada de RSS no meio.
Dunk
2
@ Dunk: é vital separar a lógica de negócios da interface do usuário para que a lógica de negócios possa ser testada diretamente.
precisa
@ Kevin: Eu concordo totalmente, a lógica de negócios não pertence à interface do usuário. No entanto, o controlador não precisa fazer parte da interface do usuário. É isso que quero dizer com muitas definições. Na definição de uma pessoa, o controlador lida com o pressionamento de botão enquanto outra pessoa colocaria isso como parte da exibição. Se a visualização souber transformar ações do operador (por exemplo, pressionar botões / seleções de elementos) em solicitações de aplicativos, o Controlador / Modelo se tornará muito reutilizável com praticamente qualquer tipo de interface do usuário, que pode incluir interfaces GUI, Console ou rede.
quer
11
@ Dunk: Suponho que você possa chamar qualquer coisa que desejar como "controlador", mas na arquitetura MVC, o controlador depende e, portanto, faz parte da interface do usuário.
precisa
7

Existem muitas maneiras diferentes de implementar esse padrão geral de design, mas a idéia básica é separar as várias preocupações conforme necessário. MVC é uma boa abstração no sentido de que:

Modelo : representa que os dados, seja lá o que pode significar
Visão : representa a interface do usuário, o que isso pode significar
Controlador : Representa a cola que causas que modelo e vista para interagir, o que isso pode significar

É extremamente flexível porque não especifica muito. Muitas pessoas desperdiçam muita largura de banda discutindo os detalhes sobre o que cada elemento pode significar, quais nomes devem ser usados ​​em vez desses e se realmente deve haver 3 ou 2 ou 4 ou 5 componentes, mas isso não faz sentido. certo grau.

A idéia é separar os diferentes "pedaços" da lógica para que eles não se sobreponham. Mantenha suas coisas de apresentação juntas, mantenha suas coisas de dados juntas, mantenha suas coisas de lógica juntas, mantenha suas coisas de comunicação juntas. E assim por diante. Até certo ponto, quanto menos essas áreas de preocupação se sobrepuserem, mais fácil será fazer coisas interessantes com elas.

É com isso que você realmente deve se preocupar.

tylerl
fonte
3
Cola, cola, eu gosto dessa definição, é tão correta: todo o modelo deveria ser batizado de MVG e as pessoas parariam de coçar a cabeça em busca de elegância, onde não há nada para encontrar.
ZJR
11
+1 para "cola"; também significa que é a parte que melhor se adequa a ser feita em uma linguagem de script (já que essas tendem a se sobressair na colagem).
Donal Fellows
@DonalFellows Eu gosto muito desse pensamento. Algo que "colas" 2 entidades díspares precisa de muita flexibilidade que fracamente tipado linguagens de script (ou seja, JavaScript) promover
Zack Macomber
4

Todas as boas respostas até agora. Meus dois centavos é que eu gosto de pensar no controlador como sendo construído principalmente com perguntas como o quê e onde?

  • Me perguntaram se uma peça de xadrez (visualização) pode ser movida para x. Isso é
    permitido? Não tenho certeza, mas sei onde e a quem perguntar (o modelo).
  • Algo me pediu para salvar meus dados. Como diabos eu faço isso? Eu sei onde perguntar embora! Como salvamos os dados, ou para onde são salvos, não faço ideia, mas essa classe de Repositório deve saber. Vou encaminhar e deixar lidar com isso.
  • Eu tenho que mostrar a posição atual da peça de xadrez para o usuário que o modelo a moveu. não tem certeza se eu quero mostrar a peça em verde ou amarelo? Bah, quem se importa, eu sei que há uma visão que pode lidar com isso, então eu passo os dados e eles podem decidir como será mostrado.

Esses pequenos trechos são exemplos de como estou tentando lembrar a abstração e o conceito que o MVC está tentando transmitir. O que, onde e como são meus três principais processos de pensamento.

O que e onde => Controlador Como e quando => Modelos e visualizações

Em essência, minhas ações de controlador tendem a ser pequenas e compactas e, ao lê-las, às vezes parecem uma perda de tempo. Em uma inspeção mais minuciosa, eles estão atuando como o homem do sinal de trânsito, canalizando as várias solicitações para os trabalhadores apropriados, mas não realizando o trabalho real.

dreza
fonte
2

Um Controller pode ajudar a abstrair as interfaces do View e do Model para que eles não precisem se conhecer diretamente. Quanto menos um objeto precisa saber, mais portátil e testável é a unidade.

Por exemplo, o Modelo pode estar executando outra instância por meio de um Controlador. Ou um Controlador em rede pode conectar os objetos Views de dois jogadores. Ou pode ser um teste de Turing em que ninguém sabe qual.

hotpaw2
fonte
2

Ele realmente entra em jogo quando você está lidando com manipuladores de eventos, mas ainda precisa do controlador para lidar com interações entre a visualização e o modelo. Idealmente, você não deseja que a visualização saiba nada sobre o modelo. Pense bem, você quer que o jsp faça todas as chamadas do banco de dados diretamente? (A menos que seja algo como uma pesquisa de logon.) Você deseja que a visualização renderize dados e não tenha nenhuma lógica comercial, a menos que seja lógica de renderização da visualização, mas não a lógica comercial.

No GWT, você obtém uma separação mais limpa com o MVP. Não há lógica comercial (se for feita corretamente) na exibição. O apresentador atua como um controlador e a visualização não tem conhecimento do modelo. Os dados do modelo são simplesmente passados ​​para a visualização.


fonte
1

A Visualização de documento (ou seja, a visualização do modelo) é o modelo padrão para a maioria dos aplicativos do Windows escritos no MFC, portanto, ele deve funcionar em muitos casos.

Martin Beckett
fonte
1

Entendo o papel do modelo e a visualização no padrão Model-View-Controller, mas tenho dificuldade em entender por que um controlador é necessário.

Você tem certeza disso? (Pelo menos, conforme descrito originalmente) O objetivo do modelo é ser o modelo de domínio. A visualização deve exibir o modelo de domínio para o usuário. O controlador deve mapear a entrada de baixo nível para a fala de modelo de alto nível. Tanto quanto posso dizer, o raciocínio é algo do tipo: A) uso de alto nível do SRP. B) O modelo foi considerado a parte importante do aplicativo, portanto, mantenha o material sem importância e a mudança mais rápida fora dele. C) lógica de negócios facilmente testável (e capaz de script).

Apenas pense se você quiser tornar seu programa de xadrez utilizável pelos cegos, troque a visualização por uma versão audível e um controlador que funcione com o teclado. Digamos que você queira adicionar jogos por correio, adicione um controlador que aceite texto. Versão líquida do jogo? Um controlador que aceita comandos de um soquete faria o trabalho. Adicione uma bela renderização 3D a ela, uma nova e interessante visão. Zero mudanças no modelo necessárias O xadrez ainda é xadrez.

Se você combinar a entrada com a representação do modelo, perderá essa capacidade. De repente, o xadrez não é xadrez, é xadrez com um mouse diferente do xadrez com um teclado ou conexão de rede.

pedregoso
fonte
0

Eu acho que o MVC é burro, talvez em áreas específicas funcione bem, mas pessoalmente até os sites que eu escrevo não são adequados para o mvc. Há uma razão pela qual você ouve front-end, back-end e nunca final de banco de dados ou algo mais final

Na IMO, deve haver uma API (back-end) e o aplicativo que usa a API (front-end). Eu acho que você poderia chamar a solicitação GET do controlador (que simplesmente chama a API de back-end) e o html como view, mas geralmente não ouço as pessoas falando sobre o modo de exibição como puro html nem o modelo sendo API de back-end.

Na IMO, tudo deve ser uma API sólida. Na verdade, eles não precisam ser sólidos (como limpos e bem construídos), mas seus internos devem permanecer privados e o aplicativo / front-end / fora da API nunca deve dizer a conexão com o banco de dados nem fazer consultas brutas.

Agora, se o seu código / design envolve cola, tudo bem. Se no seu jogo de xadrez houver alguma marcação que você possa editar para exibir a GUI, a GUI coletará as cordas / entrada e chamará MovePiece (srcPosition, dstPostion) (que pode retornar um bool ou enum para dizer se é um movimento válido ou não ) e você está bem com toda a lógica do modelo, então com certeza o chame de MVC. No entanto, eu ainda organizaria as coisas por classes e APIs e garantiria que não haja nenhuma classe de pia de cozinha que toque em tudo (nem em nenhuma API que precise saber sobre tudo).


fonte
Você é bem-vindo à sua opinião, mas esta resposta não tenta responder à pergunta do OP.
Caleb
0

Pense em um navegador que exibe uma página da web estática. O modelo é o HTML. A visualização é o resultado real na tela.

Agora adicione um pouco de JavaScript. Esse é o controlador. Quando o usuário clica em um botão ou arrasta algo que o Evento é enviado para o JavaScript, ele decide o que fazer e altera o HTML (Modelo) subjacente e o navegador / renderizador exibe essas alterações na tela (Exibir).

Talvez outro botão seja clicado, o evento é enviado para algum manipulador (Controller) e pode fazer com que uma solicitação de dados adicionais seja enviada para um serviço da web. O resultado é então adicionado ao HTML (Modelo).

O controlador responde a eventos e controla o que está no modelo e, portanto, o que está na tela / exibição.

Recuando um pouco, você pode pensar em todo o navegador como o View e o servidor como o Controller e os dados como o Model. Quando o usuário clica em um botão no navegador no evento enviado ao servidor (Controlador), reúne recursos como uma página HTML (Modelo) e envia-o de volta ao navegador para exibição (Exibir)

No servidor, seja asp, php ou java, o 'código' (Controller) recebe o evento click e consulta um banco de dados ou repositório de documentos (Model) e cria HTML. Do ponto de vista do servidor, o resultado de todas as suas ações é uma Visualização (HTML) do seu armazenamento de dados subjacente (Modelo). Mas, do ponto de vista do cliente, o resultado de sua solicitação ao servidor é o Modelo (HTML)

Mesmo se você misturar seu JavaScript no HTML ou PHP no HTML, o Model, View, Controller ainda existe. Mesmo se você pensar na sua solicitação para um servidor e na resposta do servidor como uma simples via de mão dupla, ainda haverá um Modelo, uma Visualização e um Controlador.

Zeus
fonte
-2

Na minha experiência, em um programa tradicional de desktop mvc gui, o controlador acaba sendo espaguetado na exibição. A maioria das pessoas não leva tempo para fatorar uma classe de controlador.

o livro da quadrilha de quatro diz:

Padrões de design no Smalltalk MVC

A tríade de classes Model / View / Controller (MVC) [KP88] é usada para criar interfaces de usuário no Smalltalk-80. Observar os padrões de design no MVC deve ajudá-lo a entender o que queremos dizer com o termo "padrão".

O MVC consiste em três tipos de objetos. O Model é o objeto do aplicativo, o View é a sua apresentação na tela e o Controller define a maneira como a interface do usuário reage à entrada do usuário. Antes do MVC, os designs de interface do usuário tendiam a agrupar esses objetos. O MVC os desacopla para aumentar a flexibilidade e a reutilização.

O MVC dissocia visualizações e modelos estabelecendo um protocolo de assinatura / notificação entre eles. Uma visualização deve garantir que sua aparência reflita o estado do modelo. Sempre que os dados do modelo são alterados, o modelo notifica as visualizações que dependem dele. Em resposta, cada visualização tem a oportunidade de se atualizar. Essa abordagem permite anexar várias visualizações a um modelo para fornecer apresentações diferentes. Você também pode criar novas visualizações para um modelo sem reescrevê-lo.

O diagrama a seguir mostra um modelo e três visualizações. (Deixamos de lado os controladores por simplicidade.) O modelo contém alguns valores de dados e as visualizações que definem uma planilha, histograma e gráfico de torta exibem esses dados de várias maneiras. O modelo se comunica com suas visualizações quando seus valores mudam, e as visualizações se comunicam com o modelo para acessar esses valores.

Tomado pelo valor nominal, este exemplo reflete um design que desacopla as visualizações dos modelos. Mas o design é aplicável a um problema mais geral: dissociar objetos para que as alterações em um possam afetar muitos outros, sem exigir que o objeto alterado conheça os detalhes dos outros. Esse design mais geral é descrito pelo padrão de design do Observer (página 293).

Outro recurso do MVC é que as visualizações podem ser aninhadas. Por exemplo, um painel de controle de botões pode ser implementado como uma visualização complexa contendo visualizações de botões aninhadas. A interface do usuário para um inspetor de objetos pode consistir em visualizações aninhadas que podem ser reutilizadas em um depurador. O MVC suporta visualizações aninhadas com a classe CompositeView, uma subclasse de View. Os objetos CompositeView agem exatamente como os objetos View; uma vista composta pode ser usada onde quer que uma vista possa ser usada, mas também contém e gerencia vistas aninhadas.

Novamente, poderíamos pensar nisso como um design que nos permite tratar uma visão composta, assim como tratamos um de seus componentes. Mas o design é aplicável a um problema mais geral, que ocorre sempre que queremos agrupar objetos e tratar o grupo como um objeto individual. Esse design mais geral é descrito pelo padrão de design Composite (163). Permite criar uma hierarquia de classes na qual algumas subclasses definem objetos primitivos (por exemplo, Button) e outras classes definem objetos compostos (CompositeView) que montam as primitivas em objetos mais complexos.

O MVC também permite alterar a maneira como uma visualização responde à entrada do usuário sem alterar sua apresentação visual. Você pode alterar a forma como responde ao teclado, por exemplo, ou usar um menu pop-up em vez de teclas de comando. O MVC encapsula o mecanismo de resposta em um objeto Controller. Existe uma hierarquia de classes de controladores, facilitando a criação de um novo controlador como uma variação de um existente.

Uma visão usa uma instância de uma subclasse Controller para implementar uma estratégia de resposta específica; Para implementar uma estratégia diferente, basta substituir a instância por um tipo diferente de controlador. É até possível alterar o controlador de uma visualização em tempo de execução para permitir que a visualização mude a maneira como responde à entrada do usuário. Por exemplo, uma exibição pode ser desativada para que não aceite entrada simplesmente fornecendo um controlador que ignora os eventos de entrada.

O relacionamento View-Controller é um exemplo do padrão de design da Estratégia (315). Uma estratégia é um objeto que representa um algoritmo. É útil quando você deseja substituir o algoritmo de maneira estática ou dinâmica, quando você tem muitas variantes do algoritmo ou quando o algoritmo possui estruturas de dados complexas que você deseja encapsular.

O MVC usa outros padrões de design, como o Método de fábrica (107) para especificar a classe do controlador padrão para uma visualização e o Decorator (175) para adicionar rolagem a uma visualização. Mas os principais relacionamentos no MVC são fornecidos pelos padrões de design Observer, Composite e Strategy.

Ray Tayek
fonte
11
Parece que este post inteiro, menos os dois primeiros parágrafos, foi tirado literalmente de Design Patterns . Formatei essa seção como uma citação para que os leitores entendam isso - edite se citou parágrafos que são seus.
Caleb
11
Eu tenho que discordar da sua opinião de que "o controlador acaba sendo esparramado na exibição". Talvez isso varie com a plataforma e a estrutura que você está usando, mas é muito mais comum na programação do Cocoa e do Cocoa Touch criar controladores apropriados do que omití-los. Se um programador de Objective-C omitir uma das categorias, é quase certo que seja o modelo que sofre.
Caleb
Se você concorda que esta é a interpretação "adequada" do MVC, o MVC não compra absolutamente nada. Pode ser apenas MV e deixar de fora o C, porque toda vez que você cria uma nova View, também precisa criar um novo Controller. Então, qual é o sentido de se esforçar para separá-las, exceto por razões teóricas de separação de preocupações.
quer