Por que o Qt está usando mal a terminologia de modelo / visualização?

104

Eu acho que a terminologia usada no Qt com controles de modelo / visão é falha. Em sua página de explicação, eles afirmam que simplificaram o MVC para MV ao fundir a Visualização e o Controlador e estão apresentando a seguinte imagem:

imagem explicando Qt MVC

No entanto, eu acho que eles nomearam erroneamente as funções dos objetos e acho que,

  1. O que eles chamam de Visualização com controlador mesclado é, na verdade, apenas Visualização.
  2. O que eles chamam de modelo é, na verdade, apenas controlador.
  3. Se você realmente deseja ter um modelo, ele deve estar em algum lugar onde estão os seus "Dados".

Estou falando sobre a maneira normal e sensata de usar o componente de modelo / visualização Qt em seu aplicativo. Aqui estão as razões:

  1. Este é tipicamente o componente Qt que é usado como está, sem adicionar qualquer lógica de controlador específica para seus objetos)
  2. Isso dificilmente é um modelo, apenas porque você deve implementar vários métodos Qt como rowCount, columnCount, dados etc. que não têm nada a ver com seu modelo. Na verdade, existem métodos de modelo típicos encontrados em controladores. Claro, você pode implementar a lógica do controlador e do modelo aqui, mas primeiro seria um design de código muito ruim e, em segundo lugar, você mesclaria controlador e modelo, não controlador e visualização como eles afirmam.
  3. Como dito na razão 2. se você quiser separar a lógica do modelo, certamente não é a caixa azul na imagem, mas sim a caixa "Dados" tracejada (comunicando-se com dados reais, é claro).

O Qt está errado em sua terminologia ou sou só eu que não entendo? (A propósito: a razão pela qual não é uma questão acadêmica é que eu comecei a codificar meu projeto seguindo sua nomenclatura e logo descobri que o código claramente não está certo. Foi só depois disso que percebi que deveria não tente colocar a lógica do modelo no que eles chamam de modelo)

gorn
fonte
1
O MFC definiu o padrão para o modelo / visualização de 2 partes com CDoc e CView - não há razão para que um determinado MVC seja "correto"
Martin Beckett,
@Martin B: Vou dar uma olhada no MFC, no entanto, mesmo que haja diferentes modelos MVC, acho que eles deveriam ser consistentes em sua terminologia e acho que apresentei argumentos válidos, porque a terminologia usada não é consistente neste caso particular. Eles simplesmente afirmam que combinaram View e Controller, mas acho que é simplesmente enganoso neste caso. Não acho que exista um modelo MVC em que toda a lógica específica do aplicativo, seja de apresentação ou lógica do modelo, deva ser colocada em um objeto chamado Model.
gorn
1
@Martin B: Também sob a terminiologia qt, todos os Modelos têm APIs comuns que não têm nada a ver com a estrutura do Modelo, mas tudo a ver com a estrutura geral do Controlador, o que é um sinal claro de que não é certo chamá-lo de Modelo. Não estou dizendo que existe UM modelo MVC correto, mas isso não significa que qualquer coisa pode ser chamada de modelo MVC. Talvez haja falhas no MFC também e eu posso dar uma olhada nele, mas estou mais interessado em Qt acertar, aquele MFC que não pretendo usar. Você tem algum link válido onde a separação do modelo / visualização do MFC seja explicada?
gorn
1
A terminologia MVC não é, de forma alguma, unanimemente aceita, portanto sua pergunta pode ser considerada argumentativa. Muitos concordarão, entretanto, com o excelente trabalho realizado por Martin Fowler ( martinfowler.com/eaaDev/index.html ). Normalmente, o controlador lida com a entrada do usuário e, neste sentido, os widgets Qt definitivamente combinam a visualização e o controlador.
Arnold Spence,
1
Eu entendo que MVC tem muitos sabores, mas isso não significa que qualquer coisa possa ser MVC. O Qt ultrapassou os limites e apresentei vários motivos. Martin Fowler explica diferentes tipos de MVC, mas nenhum deles é semelhante o suficiente ao que o Qt pronuncia MVC. O mais semelhante é martinfowler.com/eaaDev/PresentationModel.html , mas isso distingue entre modelo de apresentação = parte do controlador (interação do usuário) e modelo (lógica de dados). Portanto, embora não haja uma definição precisa de MVC, o Qt não segue nenhuma delas. Se você pode me dar um link para tal definição, por favor, faça-o.
gorn

Respostas:

78

Eu concordo com você que a nomenclatura do Qt é enganosa. Na minha opinião, entretanto, o problema não é apenas do Qt, mas é compartilhado por todos os frameworks que nos permitem aderir ao princípio de separação de interesses ao implementar nossas UIs. Quando alguém surge com tal estrutura e encontra uma boa maneira de manter "coisas" separadas, sempre se sente obrigado a ter módulos que chama de "Modelo" e outros que chama de "Visualização". Ao longo dos anos, trabalhei com estas estruturas:

  • MFC
  • Qt
  • Balanço
  • SWT
  • WPF com MVVM

Se você comparar como os termos "Model" e "View" são usados ​​nestes frameworks, e quais responsabilidades as classes em "View", "Model" e "Controller" (se houver) têm, você irá descobrir que existem diferenças muito grandes. Certamente seria útil ter uma comparação dos diferentes conceitos e terminologias, para que as pessoas que mudam de uma estrutura para outra tenham a chance de permanecer sãs, mas isso exigiria muito trabalho e pesquisa. Uma boa leitura é a visão geral de Martin Fowler .

Uma vez que existem tantas idéias diferentes como um padrão MVC pode se parecer, qual é a correta? Na minha opinião, as pessoas que inventaram o MVC devem ser consultadas quando quisermos saber como ele deve ser implementado "corretamente". No papel smalltalk original diz:

A visualização gerencia a saída gráfica e / ou textual para a parte da exibição em bitmap que está alocada para seu aplicativo. O controlador interpreta as entradas do mouse e do teclado do usuário, comandando o modelo e / ou a visualização para alterar conforme apropriado. Finalmente, o modelo gerencia o comportamento e os dados do domínio do aplicativo, responde às solicitações de informações sobre seu estado (geralmente da exibição) e às instruções para alterar o estado (geralmente do controlador).

À luz disso, eu responderia às suas três principais preocupações da seguinte maneira:

  1. Na verdade, um componente Qt "gerencia a saída [...] gráfica" e "interpreta as entradas do mouse e do teclado", então poderia ser chamado de Visão e Controlador mesclados com relação à definição acima.
  2. Eu concordo que você é / seria forçado a fundir Controller e Model (novamente com relação à definição acima).
  3. Eu concordo, novamente. O modelo deve gerenciar apenas os dados do domínio do aplicativo . Isso é o que eles chamam de "dados". Claramente, lidar com linhas e colunas, por exemplo, normalmente não tem nada a ver com nosso domínio de aplicativos.

Onde isso nos deixa? Na minha opinião, é melhor descobrir o que o Qt realmente significa quando os termos "Modelar" e "Visualizar" são usados ​​e usar os termos de sua maneira enquanto estamos programando com o Qt. Se você continuar sendo incomodado, isso apenas o deixará mais lento, e a maneira como as coisas são configuradas no Qt permite um design elegante - que pesa mais do que suas convenções de nomenclatura "erradas".

Tilo
fonte
2
Eu diria que o delegado é o controlador do Qt, já que os delegados recebem e enviam a entrada para o modelo, que atualiza a visualização por meio de sinais.
Peregring-lk
82

Resposta curta

O MVC do Qt só se aplica a uma estrutura de dados . Ao falar sobre um aplicativo MVC , você não deve pensar em QAbstractItemModelou QListView.

Se você deseja uma arquitetura MVC para todo o seu programa, o Qt não possui uma estrutura de modelo / visualização tão "grande". Mas para cada lista / árvore de dados em seu programa, você pode usar a abordagem Qt MVC, que de fato tem um controlador em sua visualização. Os dados estão dentro ou fora do modelo; isso depende de que tipo de modelo você está usando (própria subclasse de modelo: provavelmente dentro do modelo; por exemplo, QSqlTableModel: fora (mas talvez em cache dentro) do modelo). Para colocar seus modelos e visualizações juntos, use as próprias classes que implementam a lógica de negócios .


Resposta longa

Abordagem e terminologia do modelo / visão do Qt:

Qt fornece visualizações simples para seus modelos. Eles têm um controlador embutido: selecionar, editar e mover itens é algo que na maioria dos casos um controlador "controla". Ou seja, interpretar a entrada do usuário (cliques e movimentos do mouse) e fornecer os comandos apropriados ao modelo.

Os modelos do Qt são de fato modelos com dados subjacentes. Os modelos abstratos obviamente não armazenam dados, já que o Qt não sabe como você deseja armazená-los. Mas você estende um QAbstractItemModel às suas necessidades adicionando seus contêineres de dados à subclasse e tornando a interface do modelo acessando seus dados. Então, na verdade, e suponho que você não goste disso, o problema é que você precisa programar o modelo, então como os dados são acessados ​​e modificados em sua estrutura de dados.

Na terminologia MVC, o modelo contém os dados e a lógica . No Qt, depende de você incluir ou não parte de sua lógica de negócios dentro de seu modelo ou colocá-la fora, sendo uma "visão" por si só. Não está nem claro o que se entende por lógica: selecionar, renomear e mover itens? => já implementado. Fazendo cálculos com eles? => Colocar fora ou dentro da subclasse do modelo. Armazenando ou carregando dados de / para um arquivo? => Colocar dentro da subclasse do modelo.


Minha opinião pessoal:

É muito difícil fornecer um sistema MV (C) bom e genérico para um programador. Como na maioria dos casos os modelos são simples (por exemplo, apenas listas de strings), o Qt também fornece um QStringListModel pronto para usar. Mas se seus dados são mais complexos do que strings, você decide como deseja representar os dados por meio da interface de modelo / visualização Qt. Se você tem, por exemplo, uma estrutura com 3 campos (digamos pessoas com nome, idade e sexo), você pode atribuir os 3 campos a 3 colunas diferentes ou a 3 papéis diferentes. Não gosto de ambas as abordagens.

Acho que a estrutura de modelo / visualização do Qt só é útil quando você deseja exibir estruturas de dados simples . Torna-se difícil de manusear se os dados são de tipos personalizados ou não estruturados em uma árvore ou lista (por exemplo, um gráfico). Na maioria dos casos, as listas são suficientes e, mesmo em alguns casos, um modelo deve conter apenas uma única entrada. Especialmente se você deseja modelar uma única entrada com atributos diferentes (uma instância de uma classe), a estrutura de modelo / visualização do Qt não é a maneira certa de separar a lógica da interface do usuário.

Para resumir as coisas, eu acho que o framework de model / view do Qt é útil se e somente se seus dados estão sendo vistos por um dos widgets do viewer do Qt . É totalmente inútil se você estiver prestes a escrever seu próprio visualizador para um modelo contendo apenas uma entrada, por exemplo, as configurações do seu aplicativo, ou se seus dados não forem do tipo imprimível.


Como usei o modelo / visão Qt em um aplicativo (maior)?

Certa vez, escrevi (em equipe) um aplicativo que usa vários modelos Qt para gerenciar dados. Decidimos criar um DataRolepara conter os dados reais, que eram de um tipo personalizado diferente para cada subclasse de modelo diferente. Criamos uma classe de modelo externo chamada Modelcontendo todos os diferentes modelos Qt. Também criamos uma classe de visualização externa chamada Viewsegurando as janelas (widgets) que estão conectadas aos modelos internos Model. Portanto, esta abordagem é um Qt MVC estendido, adaptado às nossas próprias necessidades. Ambas as classes Modele Viewnão têm nada a ver com o Qt MVC.

Onde colocamos a lógica ? Criamos classes que faziam os cálculos reais nos dados lendo os dados dos modelos de origem (quando eram alterados) e gravando os resultados nos modelos de destino. Do ponto de vista do Qt, essas classes lógicas seriam visualizações, uma vez que "se conectam" aos modelos (não "visualização" para o usuário, mas uma "visualização" para a parte lógica de negócios do aplicativo).

Onde estão os controladores ? Na terminologia MVC original, os controladores interpretam a entrada do usuário (mouse e teclado) e dão comandos ao modelo para executar a ação solicitada. Como as visualizações do Qt já interpretam a entrada do usuário como renomear e mover itens, isso não era necessário. Mas o que precisávamos era de uma interpretação da interação do usuário que fosse além das visualizações do Qt.

leemes
fonte
O mais irritante é que você tem que implementar classes do modelo Qt totalmente diferentes dependendo da visão que você deseja. Um modelo para visualização de lista não oferece suporte adequado para visualização em árvore e vice-versa. Um modelo MVC canônico pode suportar uma infinidade de diferentes tipos de visualização.
smerlin
3
@smerlin: Não acho que isso seja correto. Tanto um QListView quanto um QTreeView requerem apenas uma interface QAbstractItemView, o que significa que uma subclasse personalizada dessa interface ou uma classe concreta como QStandardItemModel deve preencher esse requisito para ambos. Você pode dirigir uma árvore e listar um modelo.
jdi de
1
@jdi: há casos em que seus dados são uma lista e uma árvore ... por exemplo, você pode querer exibir seu sistema de arquivos como uma árvore ou todos os arquivos como uma lista. Os modelos Qts não permitem isso corretamente. Uma implementação de QAbstractItemModel com suporte a visualizações em árvore, permite apenas exibir todos os arquivos / diretórios em seu diretório raiz como uma lista, mas você não pode exibir todos os arquivos como uma lista. E não diga que exibir os dados da árvore como uma lista não pode ser útil. Por exemplo, você pode, por exemplo, classificá-los facilmente para localizar o arquivo com o maior tamanho de arquivo, se você exibir seus arquivos como uma lista, as visualizações em árvore não permitiriam isso.
smerlin
1
Dito isso, o modelo de proxy é mais algo da sua visão (uma vez que modifica como os dados são visualizados ) e, portanto, deve pertencer à sua visão. Se você leu minha longa resposta: Na Viewclasse "grande", você deve adicionar o modelo de proxy, que tem o modelo de árvore como modelo subjacente e é usado pela exibição de lista do sistema de arquivos. Como você está dizendo: não deve haver dois modelos para os mesmos dados. Nunca! (Mas modelos de proxy não contam como modelos separados.)
leemes de
1
@SamPinkus Isso porque não um sim ou não claro para essa pergunta. Além disso, existem diferentes implementações de QAbstractItemModel, algumas das quais são modelos no sentido de MVC e outras não.
leemes
12

A terminologia não é certa ou errada, é útil ou inútil.

Você pode mudar um pouco a questão e perguntar por que o Qt não é mais amigável com MVC. A resposta é que os primeiros desenvolvedores do Qt acreditam que desacoplar V de C em aplicativos GUI prejudica Vs e Cs. O design do QWidget tenta simplificar a vinculação da interação de entrada do mouse com as decisões de saída de pixel, e você pode ver como esse não é o caminho para o MVC.

arnt
fonte
Eu vejo seu ponto e basicamente eu perguntaria por que o Qt não é mais amigável ao MVC, mas é muito difícil fazer quando a terminologia MVC usada na documentação do Qt é DIFERENTE de como o MVC é normalmente usado (como expliquei na pergunta). E quando há terminologia amplamente usada e alguém a usa de maneira muito diferente do resto do mundo, tendo a pensar que não é apenas inútil, mas que é totalmente ERRADO e confuso (essa confusão me levou a fazer a pergunta no primeiro Lugar, colocar). Eu estaria muito interessado se você tivesse algum link para essas coisas sendo discutidas ou explicadas em algum lugar. Obrigado
gorn
Não posso dizer nada sobre por que os documentos Qt agora falam sobre MVC da maneira que o fazem. Deixei a Trolltech há muito tempo e estou intrigado com algumas das coisas que foram feitas com a documentação desde que saí. (No meu blog eu às vezes discuto um pouco sobre isso.)
arnt
Você tem alguma ideia de como a terminologia MVC foi acordada no Qt. Foi usado durante a escrita do código ou apenas mais tarde durante o processo de documentação.
gorn
Não usamos a palavra "MVC" na documentação do Qt durante meu tempo na Trolltech. Em geral, acho melhor documentar o que está lá, não escrever sobre o que não está. No entanto, em gitorious você pode descobrir quem adicionou aquele texto e adicionar essa pessoa diretamente.
arnt
1
Um comentário diferente. Discutimos MVC durante o design e a frase de implementação inicial do Qt (quando a Trollech era uma empresa de três pessoas), e avaliamos um kit de ferramentas de GUI que usava MVC "corretamente", não consigo lembrar o nome. Nossa opinião era que aquele kit de ferramentas era terrível de usar e que o MVC era o principal motivo para isso.
arnt
3

Como a função de Model é responder a solicitações de informações, acho que não há nada de errado em definir métodos como rowCount, columnCountetc. Acho que Model é algum tipo de invólucro para fonte de dados (não importa o que seja uma tabela SQL ou apenas um array) , ele fornece dados no formato padrão, e você deve definir os métodos de acordo com a estrutura da fonte de dados.

Dmitry
fonte
2

Eu acredito que a terminologia deles está correta ... embora em aplicações reais eu ache que pode ser muito fácil borrar as linhas entre o modelo, a visão e o controlador dependendo do seu nível de abstração: a visão de um nível pode ser o modelo de um nível superior.

Acho que a confusão surge de sua classe QAbstractModelItem. Esta classe não é um item de modelo, mas sim uma interface para um modelo. Para fazer a interface de suas classes de visualização com o modelo, eles tiveram que criar uma interface abstrata genérica para o modelo. Porém, um modelo pode ser um único item, uma lista de itens, uma tabela de 2 ou mais dimensões de itens, etc; portanto, sua interface deve suportar todas essas variações de modelo. Reconhecidamente, isso torna os itens do modelo bastante complexos, e o código-cola para fazê-lo funcionar com um modelo real parece esticar um pouco a metáfora.

Chris Morlier
fonte
Embora eu concorde com você com a classe QAbstractModelItem, também acho que, mesmo sem essa complicação, seu MVC tem nome incorreto. Você poderia explicar porque você acha que a terminologia deles está correta. Eu adoraria saber por que não estou correto em nenhum dos meus três argumentos.
gorn
0

Eu acho que ... O que eles chamam de Modelo é, na verdade, apenas controlador.

Não, seu "modelo" definitivamente não é um controlador.

O controlador é a parte dos controles visíveis do usuário que modificam o modelo (e, portanto, modificam indiretamente a visualização). Por exemplo, um botão "excluir" faz parte do controlador.

Acho que muitas vezes há confusão porque muitos veem algo como "o controlador modifica o modelo" e acham que isso significa as funções mutantes em seu modelo, como um método "deleteRow ()". Mas no MVC clássico, o controlador é especificamente a parte da interface do usuário. Os métodos que alteram o modelo são simplesmente parte do modelo.

Desde que o MVC foi inventado, sua distinção entre controlador e visualização tornou-se cada vez mais tensa. Pense em uma caixa de texto: ela mostra algum texto e permite que você edite, então é uma visualização ou controlador? A resposta tem que ser que faz parte de ambos. Quando você estava trabalhando em um teletipo na década de 1960, a distinção era mais clara - pense no ed- mas isso não significa que as coisas eram melhores para o usuário naquela época!

É verdade que seu QAbstractItemModel é um nível bastante mais alto do que um modelo normalmente seria. Por exemplo, os itens nele podem ter uma cor de fundo (um pincel, tecnicamente), o que é decididamente um atributo visual! Portanto, há um argumento de que QAbstractItemModel é mais como uma visualização e seus dados são o modelo. A verdade é que está em algum lugar entre os significados clássicos de visão e modelo. Mas não consigo ver como é um controlador; se alguma coisa é o widget QT que o usa.

Arthur Tacca
fonte