Acho que entendo os conceitos básicos do MVC - o Modelo contém os dados e o comportamento do aplicativo, o View é responsável por exibi-lo ao usuário e o Controller lida com a entrada do usuário. O que não tenho certeza é exatamente o que se passa no controlador.
Digamos, por exemplo, que eu tenho um aplicativo bastante simples (estou pensando especificamente em Java, mas suponho que os mesmos princípios se apliquem em outros lugares). Organizo meu código em 3 pacotes chamados app.model
, app.view
e app.controller
.
Dentro do app.model
pacote, tenho algumas classes que refletem o comportamento real do aplicativo. Eles extends Observable
usam setChanged()
e notifyObservers()
acionam as visualizações para atualizar quando apropriado.
O app.view
pacote possui uma classe (ou várias classes para diferentes tipos de exibição) que usa javax.swing
componentes para manipular a exibição. Alguns desses componentes precisam ser realimentados no modelo. Se bem entendi, o View não deve ter nada a ver com o feedback - isso deve ser tratado pelo Controlador.
Então, o que eu realmente coloco no Controller? Coloco o public void actionPerformed(ActionEvent e)
na View com apenas uma chamada para um método no Controller? Em caso afirmativo, alguma validação etc deve ser feita no Controlador? Em caso afirmativo, como retorno as mensagens de erro de volta ao View - isso deve passar pelo Modelo novamente ou o Controlador deve enviá-lo diretamente de volta ao View?
Se a validação for feita na View, o que devo colocar no Controller?
Desculpe pela longa pergunta, eu só queria documentar minha compreensão do processo e espero que alguém possa esclarecer esse problema para mim!
fonte
O problema
MVC
é que as pessoas pensam que a visão, o controlador e o modelo devem ser o mais independentes possível um do outro. Eles não pensam nisso como uma visão e um controlador frequentemente interligadosM(VC)
.O controlador é o mecanismo de entrada da interface do usuário, que geralmente é embaraçado na visualização, principalmente nas GUIs. No entanto, a visualização é emitida e o controlador é inserido. Uma visão geralmente pode funcionar sem um controlador correspondente, mas um controlador geralmente é muito menos útil sem uma visão. Os controladores amigáveis usam a visualização para interpretar as informações do usuário de uma maneira mais significativa e intuitiva. É isso que dificulta a separação do conceito de controlador da visualização.
Pense em um robô controlado por rádio em um campo de detecção em uma caixa selada como o modelo.
O modelo é sobre transições de estado e estado sem conceito de saída (exibição) ou o que está acionando as transições de estado. Posso obter a posição do robô em campo e o robô sabe como mudar de posição (dê um passo à frente / para trás / esquerda / direita. Fácil de visualizar sem uma vista ou um controlador, mas não faz nada útil
Pense em uma visão sem um controlador, por exemplo, alguém em outra sala da rede em outra sala assistindo o robô se posicionar enquanto as coordenadas (x, y) fluem em um console de rolagem. Essa visualização está apenas exibindo o estado do modelo, mas esse cara não tem controlador. Novamente, é fácil visualizar essa visão sem um controlador.
Pense em um controlador sem visão, por exemplo, alguém trancado em um armário com o controlador de rádio sintonizado na frequência do robô. Este controlador está enviando entrada e causando transições de estado sem ter idéia do que está fazendo no modelo (se houver). Fácil de visualizar, mas não é realmente útil sem algum tipo de feedback da visualização.
A maioria das interfaces de usuário amigáveis coordena a visualização com o controlador para fornecer uma interface de usuário mais intuitiva. Por exemplo, imagine uma visualização / controlador com uma tela sensível ao toque mostrando a posição atual do robô em 2-D e permitindo que o usuário toque no ponto na tela que está na frente do robô. O controlador precisa de detalhes sobre a visualização, por exemplo, a posição e a escala da viewport e a posição do pixel tocado em relação à posição do pixel do robô na tela) para interpretar isso corretamente (ao contrário do cara trancado no armário com o controlador de rádio).
Eu já respondi sua pergunta? :-)
O controlador é qualquer coisa que recebe entrada do usuário usada para fazer com que o modelo faça a transição do estado. Tente manter a visão e o controlador separados, mas perceba que eles geralmente são interdependentes entre si, por isso não há problema se o limite entre eles é nebuloso, ou seja, ter a visão e o controlador como pacotes separados pode não ser tão limpo quanto você faria. como, mas tudo bem. Você pode ter que aceitar que o controlador não será separado da visão como é do modelo.
Eu digo que uma visão vinculada e um controlador devem interagir livremente sem passar pelo modelo. O controlador recebe a entrada do usuário e deve fazer a validação (talvez usando informações do modelo e / ou da visualização), mas se a validação falhar, o controlador poderá atualizar sua visualização relacionada diretamente (por exemplo, mensagem de erro).
O teste de ácido para isso é perguntar a si mesmo se uma visão independente (ou seja, o cara na outra sala assistindo a posição do robô pela rede) deve ver alguma coisa ou não como resultado do erro de validação de outra pessoa (por exemplo, o cara no armário) tentou dizer ao robô para sair do campo). Geralmente, a resposta é não - o erro de validação impediu a transição de estado. Se não houve transição de estado (o robô não se moveu), não há necessidade de informar os outros pontos de vista. O cara no armário simplesmente não recebeu nenhum feedback de que ele tentou causar uma transição ilegal (sem visão - interface do usuário ruim), e ninguém mais precisa saber disso.
Se o cara com a tela sensível ao toque tentou enviar o robô para fora do campo, ele recebeu uma boa mensagem amigável pedindo que não matasse o robô enviando-o para fora do campo de detecção, mas, novamente, ninguém mais precisa saber disso.
Se outros pontos de vista que precisa de saber sobre esses erros, então você está efetivamente dizendo que as entradas do usuário e quaisquer erros resultantes são parte do modelo e toda a coisa é um pouco mais complicado ...
fonte
Aqui está um bom artigo sobre o básico do MVC.
Afirma ...
Em outras palavras, sua lógica de negócios. O controlador responde às ações do usuário executadas na visualização e responde. Coloque a validação aqui e selecione a exibição apropriada se a validação falhar ou for bem-sucedida (página de erro, caixa de mensagem, o que for).
Há outro bom artigo na Fowler .
fonte
O padrão MVC deseja apenas que você separe a apresentação (= visualização) da lógica de negócios (= modelo). A parte do controlador está lá apenas para causar confusão.
fonte
Na prática, nunca achei o conceito de controlador particularmente útil. Eu uso uma separação estrita de modelo / exibição no meu código, mas não há um controlador claramente definido. Parece ser uma abstração desnecessária.
Pessoalmente, o MVC completo parece o padrão de design de fábrica, pois leva facilmente a um design confuso e muito complicado. Não seja um astronauta de arquitetura .
fonte
Com base na sua pergunta, tenho a impressão de que você está um pouco confuso com o papel do modelo. O Modelo é fixado nos dados associados ao aplicativo; se o aplicativo tiver um banco de dados, o trabalho do modelo será conversar com ele. Ele também manipulará qualquer lógica simples associada a esses dados; se você tem uma regra que diz que em todos os casos em que TABLE.foo == "Viva!" e TABLE.bar == "Huzzah!" depois defina TABLE.field = "W00t!", então você quer que o Model cuide dele.
O Controller é o que deve lidar com a maior parte do comportamento do aplicativo. Então, para responder às suas perguntas:
Eu diria que não. Eu diria que deveria morar no Controller; o View deve simplesmente alimentar os dados provenientes da interface do usuário no Controller e deixar o Controller decidir quais métodos devem ser chamados em resposta.
A maior parte da sua validação realmente deve ser feita pelo Controlador; deve responder à questão de saber se os dados são válidos ou não e, se necessário, alimentar as mensagens de erro apropriadas para a Visualização. Na prática, você pode incorporar algumas verificações simples de sanidade na camada Exibir para melhorar a experiência do usuário. (Estou pensando principalmente em ambientes da web, nos quais você pode querer exibir uma mensagem de erro no momento em que o usuário clica em "Enviar" em vez de aguardar todo o ciclo de envio -> processo -> carregamento da página antes de dizer a eles que estão errados .) Apenas tenha cuidado; você não deseja duplicar esforços além do necessário, e em muitos ambientes (novamente, estou pensando na web), muitas vezes é necessário tratar todos os dados provenientes da interface do usuário como um pacote de imundos e imundos. mente até você
Você deve ter algum protocolo configurado em que o View não saiba necessariamente o que acontece a seguir até que o Controller informe. Qual tela você mostra depois que o usuário aperta esse botão? O View pode não saber, e o Controller também pode não saber até olhar para os dados que acabou de obter. Pode ser "Vá para outra tela, conforme o esperado" ou "Permaneça nesta tela e exiba esta mensagem de erro".
Na minha experiência, a comunicação direta entre o Modelo e a Visualização deve ser muito, muito limitada, e a Visualização não deve alterar diretamente nenhum dado do Modelo; esse deve ser o trabalho do controlador.
Veja acima; a validação real deve estar no controlador. E espero que você tenha alguma idéia do que deve ser colocado no Controlador agora. :-)
Vale a pena notar que tudo pode ficar um pouco embaçado nas bordas; como em quase tudo tão complexo quanto a engenharia de software, haverá muitas solicitações de julgamento. Apenas use seu bom senso, tente manter a consistência dentro deste aplicativo e tente aplicar as lições que aprenderá no próximo projeto.
fonte
O controlador é realmente parte do modo de exibição. Seu trabalho é descobrir quais serviços são necessários para atender à solicitação, desmarcar valores da View em objetos que a interface de serviço requer, determinar a próxima View e organizar a resposta de volta para um formato que a próxima View possa usar . Ele também lida com todas as exceções lançadas e as renderiza em Visualizações que os usuários podem entender.
A camada de serviço é o que conhece os casos de uso, unidades de trabalho e objetos de modelo. O controlador será diferente para cada tipo de visualização - você não terá o mesmo controlador para UIs de desktop, navegador, Flex ou móvel. Então eu digo que é realmente parte da interface do usuário.
Orientado a serviços: é aí que o trabalho é feito.
fonte
O controlador é principalmente para coordenação entre a vista e o modelo.
Infelizmente, às vezes acaba sendo misturado com a exibição - em aplicativos pequenos, embora isso não seja tão ruim.
Eu sugiro que você coloque o:
no controlador. Em seguida, seu ouvinte de ação na sua exibição deve delegar para o controlador.
Quanto à parte da validação, você pode colocá-lo na visualização ou no controlador, pessoalmente acho que ele pertence ao controlador.
Eu recomendaria definitivamente dar uma olhada no Passive View e no Supervising Presenter (que é essencialmente o que o Model View Presenter está dividido - pelo menos por Fowler). Vejo:
http://www.martinfowler.com/eaaDev/PassiveScreen.html
http://www.martinfowler.com/eaaDev/SupervisingPresenter.html
fonte
Aqui está uma regra prática que eu uso: se for um procedimento que usarei especificamente para uma ação nesta página, ele pertence ao controlador, não ao modelo. O modelo deve fornecer apenas uma abstração coerente para o armazenamento de dados.
Eu inventei isso depois de trabalhar com um aplicativo da Web grande escrito por desenvolvedores que pensavam que eram entendidos em MVC, mas realmente não. Seus "controladores" são reduzidos a oito linhas de chamada de métodos de classe estática que normalmente não são chamados em nenhum outro lugar: - / tornando seus modelos pouco mais do que maneiras de criar espaços para nome. A refatoração correta faz três coisas: muda todo o SQL para a camada de acesso a dados (também conhecido como modelo), torna o código do controlador um pouco mais detalhado, mas muito mais compreensível, e reduz os antigos arquivos "modelo" a nada. :-)
fonte
Observe também que cada widget Swing pode ser considerado como contendo os três componentes MVC: cada um possui um Model (por exemplo, ButtonModel), uma View (BasicButtonUI) e um Control (o próprio JButton).
fonte
Você está essencialmente certo sobre o que coloca no controlador. É a única maneira que o Modelo deve interagir com a Visualização. O actionperformed pode ser colocado na View, mas a funcionalidade real pode ser colocada em outra classe que atuaria como Controller. Se você fizer isso, recomendo examinar o padrão Command, que é uma maneira de abstrair todos os comandos que possuem o mesmo receptor. Desculpe pela digressão.
De qualquer forma, uma implementação MVC adequada terá apenas as seguintes interações: Modelo -> Exibir Visualização -> Controller Controller -> View
O único lugar em que pode haver outra interação é se você usar um observador para atualizar a Visualização, então a Visualização precisará solicitar ao Controlador as informações necessárias.
fonte
Pelo que entendi, o Controller traduz de ações da interface do usuário para ações no nível do aplicativo. Por exemplo, em um videogame, o Controller pode traduzir "moveu o mouse tantos pixels" para "deseja olhar em tal e qual direção. Em um aplicativo CRUD, a tradução pode ser" clicada em tal e tal botão "para "imprima essa coisa", mas o conceito é o mesmo.
fonte
Fazemos isso assim, usando Controladores principalmente para manipular e reagir a ações / entradas orientadas pelo usuário (e _Logic para todo o resto, exceto exibição, dados e coisas óbvias sobre _Model):
(1) (resposta, reação - o que o aplicativo da web "faz" em resposta ao usuário) Blog_Controller
-> principal ()
-> handleSubmit_AddNewCustomer ()
-> confirmUser_HasProperAuth ()
(2) (lógica "comercial", o que e como o webapp "pensa") Blog_Logic
-> sanityCheck_AddNewCustomer ()
-> handleUsernameChange ()
-> sendEmail_NotifyRequestedUpdate ()
(3) (visualizações, portais, como o aplicativo da Web "aparece") Blog_View
-> genWelcome ()
-> genForm_AddNewBlogEntry ()
-> genPage_DataEntryForm ()
(4) (apenas objeto de dados, adquirido em _ construct () de cada Blog classe *, usado para manter todos os dados de aplicativos da web / memória juntos como um objeto) Blog_Meta
(5) (camada de dados básica, lê / grava em bancos de dados) Blog_Model
-> saveDataToMemcache ()
-> saveDataToMongo ()
-> saveDataToSql ()
-> loadData ()
Às vezes, ficamos um pouco confusos sobre onde colocar um método, no C ou no L. Mas o Modelo é sólido como uma rocha, claro como cristal e, como todos os dados na memória residem no _Meta, também é um acéfalo. . Nosso maior salto adiante foi a adoção do uso do _Meta, a propósito, já que isso eliminava todo o ruído dos vários objetos _C, _L e _Model, tornando tudo mentalmente fácil de gerenciar, além disso, de uma só vez, nos deu o que estava sendo chamado "Injeção de Dependência", ou uma maneira de repassar um ambiente inteiro junto com todos os dados (cujo bônus é a criação fácil do ambiente de "teste").
fonte