MVC (Model, View, Controller) é um padrão para organizar o código em um aplicativo para melhorar a capacidade de manutenção.
Imagine um fotógrafo com sua câmera em um estúdio. Um cliente pede que ele tire uma foto de uma caixa.
Arquiteturas não MVC tendem a ser fortemente integradas. Se a caixa, o controlador e a câmera fossem o mesmo objeto, teríamos que nos separar e reconstruir a caixa e a câmera sempre que desejássemos obter uma nova visualização. Além disso, tirar a foto sempre seria como tirar uma selfie - e isso nem sempre é muito fácil.
bwaha escreveu:
O autor se refere ao mvctree.py no wxPython como um exemplo de design do MVC. No entanto, ainda sou muito verde, então acho esse exemplo específico muito complexo e não estou entendendo a separação que o autor está recomendando.
MVC é tudo sobre separação de preocupações.
O Modelo é responsável pelo gerenciamento dos dados do programa (dados privados e do cliente). O View / Controller é responsável por fornecer ao mundo externo os meios para interagir com os dados do cliente do programa.
O Modelo fornece uma interface interna (API) para permitir que outras partes do programa interajam com ele. O View / Controller fornece uma interface externa (GUI / CLI / formulário da web / IPC de alto nível / etc.) Para permitir que tudo o que o programa comunique com ele.
O Modelo é responsável por manter a integridade dos dados do programa, porque se isso for corrompido, o jogo terminará para todos. O View / Controller é responsável por manter a integridade da interface do usuário, garantindo que todas as exibições de texto estejam exibindo valores atualizados, desativando itens de menu que não se aplicam ao foco atual, etc.
O modelo não contém código de visualização / controlador; sem classes de widget da GUI, sem código para colocar caixas de diálogo ou receber entrada do usuário. O View / Controller não contém código de modelo; nenhum código para validar URLs ou executar consultas SQL e também nenhum estado original: quaisquer dados mantidos pelos widgets são apenas para fins de exibição e apenas um reflexo dos dados verdadeiros armazenados no Modelo.
Agora, aqui está o teste de um verdadeiro projeto MVC: o programa deve, em essência, ser totalmente funcional, mesmo sem um View / Controller conectado. OK, o mundo externo terá problemas para interagir com ele dessa forma, mas desde que se conheça os encantamentos apropriados da API de modelo, o programa manterá e manipulará os dados normalmente.
Por que isso é possível? Bem, a resposta simples é que tudo isso se deve ao baixo acoplamento entre as camadas Model e View / Controller. No entanto, esta não é a história completa. A chave para todo o padrão MVC é a direção na qual essas conexões vão: TODAS as instruções fluem da View / Controller para o Model. O modelo NUNCA diz ao View / Controller o que fazer.
Por quê? Porque no MVC, enquanto o View / Controller tem permissão para conhecer um pouco sobre o Model (especificamente, a API do Model), mas o Model não tem permissão para saber nada sobre o View / Controller.
Por quê? Porque o MVC é sobre a criação de uma clara separação de preocupações.
Por quê? Para ajudar a impedir que a complexidade do programa fique fora de controle e enterre você, o desenvolvedor, sob ele. Quanto maior o programa, maior o número de componentes nesse programa. E quanto mais conexões existirem entre esses componentes, mais difícil será para os desenvolvedores manter / estender / substituir componentes individuais ou apenas seguir como o sistema inteiro funciona. Pergunte a si mesmo: ao olhar para um diagrama da estrutura do programa, você prefere ver uma árvore ou o berço de um gato? O padrão MVC evita o último, impedindo conexões circulares: B pode conectar-se a A, mas A não pode conectar-se a B. Nesse caso, A é o modelo e B é o View / Controller.
BTW, se você for perspicaz, notará um problema com a restrição 'unidirecional' descrita: como o Modelo pode informar o View / Controller sobre alterações nos dados do usuário do Modelo quando ele nem sequer tem permissão para sabe que o View / Controller, não importa enviar mensagens para ele? Mas não se preocupe: existe uma solução para isso, e é bastante elegante, mesmo que pareça um pouco indireta no começo. Voltaremos a isso em um momento.
Em termos práticos, então, um objeto View / Controller pode, através da API do Modelo, 1. dizer ao Modelo para fazer as coisas (executar comandos) e 2. Diga ao Modelo para dar as coisas (retornar dados). A camada View / Controller
envia instruções para a camada Model e extrai informações da camada Model.
E é aí que o seu primeiro exemplo MyCoolListControl der errado, porque a API para essa classe requer que as informações sejam empurrados
para ele, então você está de volta a ter um acoplamento de duas vias entre as camadas, violando as regras MVC e despejar-lo de volta para o arquitetura do berço do gato que você estava [presumivelmente] tentando evitar em primeiro lugar.
Em vez disso, a classe MyCoolListControl deve seguir o fluxo, puxando os dados necessários da camada abaixo, quando necessário. No caso de um widget de lista, isso geralmente significa perguntar quantos valores existem e, em seguida, solicitar cada um desses itens, porque essa é a maneira mais simples e mais simples de fazê-lo e, portanto, mantém o mínimo de acoplamento. E se o widget quiser, digamos, apresentar esses valores ao usuário em boa ordem alfabética, então isso é perogativo; e sua responsabilidade, é claro.
Agora, um último enigma, como sugeri anteriormente: como você mantém a exibição da interface do usuário sincronizada com o estado do modelo em um sistema baseado em MVC?
Aqui está o problema: muitos objetos View são stateful, por exemplo, uma caixa de seleção pode estar marcada ou desmarcada, um campo de texto pode conter algum texto editável. No entanto, o MVC determina que todos os dados do usuário sejam armazenados na camada Modelo, portanto, quaisquer dados mantidos por outras camadas para fins de exibição (o estado da caixa de seleção, o texto atual do campo de texto) devem, portanto, ser uma cópia subsidiária desses dados primários do Modelo. Mas se o estado do modelo mudar, a cópia desse estado não será mais precisa e precisará ser atualizada.
Mas como? O padrão MVC impede que o Modelo envie uma cópia nova dessas informações para a camada Visualizar. Caramba, ele nem sequer permite que o Modelo envie uma mensagem para a View dizendo que seu estado mudou.
Bem, quase. Ok, a camada Model não pode falar diretamente com outras camadas, pois isso exigiria que ele soubesse algo sobre essas camadas, e as regras do MVC evitam isso. No entanto, se uma árvore cai em uma floresta e ninguém está por perto para ouvi-la, ela soa?
A resposta, você vê, é configurar um sistema de notificações, fornecendo à camada Model um local que ela pode anunciar a ninguém em particular que acabou de fazer algo interessante. Outras camadas podem postar ouvintes com esse sistema de notificação para ouvir os anúncios nos quais eles realmente estão interessados. A camada Model não precisa saber nada sobre quem está ouvindo (ou mesmo se alguém está ouvindo!); apenas publica um anúncio e depois esquece. E se alguém ouvir esse anúncio e sentir vontade de fazer algo depois - como pedir ao modelo novos dados para que ele possa atualizar sua exibição na tela -, então ótimo. O Modelo apenas lista quais notificações ele envia como parte de sua definição de API; e o que mais alguém faz com esse conhecimento depende deles.
O MVC é preservado e todos estão felizes. Sua estrutura de aplicativos pode muito bem fornecer um sistema de notificações embutido ou você pode escrever seu próprio, se não (consulte o 'padrão de observador').
...
Enfim, espero que ajude. Depois de entender as motivações por trás do MVC, as razões pelas quais as coisas são feitas da maneira que são começam a fazer sentido, mesmo quando - à primeira vista - elas parecem mais complexas do que o necessário.
Felicidades,
tem