Arquitetura limpa: o que é o modelo de exibição?


13

Em seu livro 'Arquitetura limpa', o tio Bob diz que o apresentador deve colocar os dados que recebe em algo que ele chama de 'modelo de exibição'.

insira a descrição da imagem aqui

É o mesmo que o 'ViewModel' do padrão de design Model-View-ViewModel (MVVM) ou é um simples Data Transfer Object (DTO)?

Se é não um simples DTO, como ele se relaciona com a View? A visualização obtém atualizações através de um relacionamento de Observador?

Meu palpite é que é mais parecido com o ViewModel do MVVM, porque no capítulo 23 de seu livro, Robert Martin diz:

O trabalho [do apresentador] é aceitar dados do aplicativo e formatá-los para apresentação, para que o View possa simplesmente movê-los para a tela. Por exemplo, se o aplicativo desejar exibir uma data em um campo, ele entregará ao apresentador um objeto Data. O Presenter formatará esses dados em uma sequência apropriada e os colocará em uma estrutura de dados simples chamada modelo View, onde a View pode encontrá-los.

Isso implica que o View esteja de alguma forma conectado ao ViewModel, em vez de simplesmente recebê-lo como um argumento de função, por exemplo (como seria o caso de um DTO).

Outro motivo pelo qual acho que isso ocorre porque, se você olhar para a imagem, o Presenter usa o View Model, mas não o View. Considerando que os usos do apresentador tanto a saída limite e a saída de dados DTO.

Se não é um DTO nem o ViewModel do MVVM, por favor, descreva o que é.


Eu acho que a resposta é "depende". Se for um aplicativo da Web, um modelo de visualização é basicamente um DTO, porque, em última análise, é serializado como uma string HTML. Caso contrário, um modelo de vista é apenas um objeto especializado para exibir os dados na vista.
Greg Burghardt

Em MVVM (WPF, aplicações WinForms) ViewModelé wrapper para Controller, Presentere ViewModelem arquitetura limpa do tio Bob.
Fabio

@ Greg Burghardt - Quando o ViewModel é uma estrutura de dados especializada, como o View é notificado de alterações?
Fearnbuster 19/10/19

@ Fabio - Se eu entendi corretamente, você está dizendo que, no padrão MVVM, o ViewModel é equivalente a todos os componentes que estão dentro do grupo mais à esquerda do diagrama? Se isso é verdade para a arquitetura do tio Bob, por que ele lista o controlador e o apresentador separadamente?
Fearnbuster 19/10/19

Eu acho que ele separou os manipuladores de entrada e saída em diferentes objetos / classes. No MVVM pode ser Controller-> ICommande Presenter-> data-binding mechanism.
Fabio

Respostas:


17

É o mesmo que o 'ViewModel' do padrão de design do Model-View-ViewModel (MVVM)

Não.

Isso seria o seguinte :

insira a descrição da imagem aqui

Isso tem ciclos. O tio Bob tem evitado cuidadosamente os ciclos .

Em vez disso, você tem o seguinte:

insira a descrição da imagem aqui

O que certamente não tem ciclos. Mas está deixando você se perguntando como a exibição sabe sobre uma atualização. Chegaremos a isso em um momento.

ou é um simples objeto de transferência de dados (DTO)?

Para citar Bob da página anterior:

Você pode usar estruturas básicas ou objetos simples de transferência de dados, se quiser. Ou você pode empacotá-lo em um hashmap ou construí-lo em um objeto.

Arquitetura Limpa p207

Então, claro, se você quiser.

Mas eu suspeito fortemente o que realmente está incomodando você é o seguinte :

insira a descrição da imagem aqui

Esse pequeno abuso da UML contrasta a direção da dependência do código-fonte com a direção do fluxo de controle. É aqui que a resposta para sua pergunta pode ser encontrada.

Em um relacionamento de uso:

insira a descrição da imagem aqui insira a descrição da imagem aqui

o fluxo de controle segue na mesma direção que a dependência do código fonte.

Em um relacionamento de implementação:

insira a descrição da imagem aqui insira a descrição da imagem aqui

o fluxo de controle normalmente segue na direção oposta à da dependência do código-fonte.

O que significa que você está realmente olhando para isso:

insira a descrição da imagem aqui

Você deve conseguir ver que o fluxo de controle nunca vai passar do Apresentador para a Visualização.

Como pode ser? O que isso significa?

Isso significa que a visualização possui seu próprio encadeamento (o que não é incomum) ou (como o @Euphoric aponta) o fluxo de controle está entrando na visualização de algo mais não descrito aqui.

Se for o mesmo thread, o View saberá quando o View-Model está pronto para ser lido. Mas, se esse for o caso, e a visualização for uma GUI, será difícil repintar a tela quando o usuário a mover enquanto espera pelo banco de dados.

Se a visualização tiver seu próprio encadeamento, ele terá seu próprio fluxo de controle. Isso significa que, para implementar isso, o View precisará pesquisar o View-Model para observar as alterações.

Como o apresentador não sabe que a exibição existe e a exibição não sabe que o apresentador existe, eles não podem se ligar. Eles não podem arremessar eventos um para o outro. Tudo o que pode acontecer é que o Presenter gravará no View-Model e o View lerá o View-Model. Sempre que lhe apetecer.

De acordo com este diagrama, a única coisa que o View e o Presenter compartilham é o conhecimento do View-Model. E é apenas uma estrutura de dados. Portanto, não espere que ele tenha algum comportamento.

Isso pode parecer impossível, mas pode funcionar mesmo que o View-Model seja complexo. Um pequeno campo atualizado é tudo o que a visualização teria que pesquisar para detectar uma alteração.

Agora, é claro, você pode insistir em usar o padrão de observador ou ter alguma coisa estruturada para esconder esse problema, mas entenda que não precisa.

Aqui está um pouco de diversão que ilustrei o fluxo de controle:

insira a descrição da imagem aqui

Observe que sempre que você vê o fluxo indo contra as direções definidas anteriormente, o que você vê é uma chamada retornando. Esse truque não nos ajudará a chegar ao ponto de vista. Bem, a menos que voltemos ao que chamamos de Controller. Ou você pode simplesmente mudar o design para poder acessar a visualização. Isso também corrige o que parece ser o início de um problema de ioiô com o Data Access e sua interface.

A única outra coisa a aprender aqui, além disso, é que o Use Case Interactor pode praticamente chamar as coisas na ordem que quiser, desde que o último seja o apresentador.


Muito obrigado pela resposta, cara, eu já vi suas respostas em várias outras perguntas sobre a Arquitetura Limpa. Você está sugerindo que o View verifique constantemente um sinalizador, por exemplo, no View Model para ver se houve alguma alteração? A visualização precisaria exibir novamente o Modelo de Visualização inteiro novamente ou devo usar um conjunto de sinalizadores aninhados para indicar quais dados foram alterados?
Fearnbuster 19/10/19

A vista não precisa pesquisar constantemente. Por exemplo, a web 1.0 é pesquisada apenas quando o usuário pressiona recarregar. A busca constante é uma decisão de design que deve considerar as reais necessidades dos usuários. Só estou dizendo que é possível. O objetivo de um campo de atualização é acelerar a detecção de uma atualização. Necessário apenas se o View Model for complexo. Considere também o que acontece se a exibição ler enquanto o apresentador estiver no meio de uma atualização.
Candied_orange 19/10/19

Ok, muito obrigado pela ajuda. Se / quando você seguir essa arquitetura, essa é a técnica que você costuma usar?
Fearnbuster 19/10/19

1
Eu acho que há um grande erro que essa resposta agrupe dependência de design e dependência de tempo de execução. Os dois podem ser diferentes.
Euphoric

1
@Euphoric Por que obrigado. Estou vinculando-os porque, se você não tem uma dependência do código-fonte de algo, não pode usar uma referência de tempo de execução para nada, pois não entende o que é. Tudo o que você pode fazer é manter a referência como uma coleção. Se isso é um erro, eu gostaria de entender.
candied_orange

2

Acho esse problema muito confuso e levaria muito texto e tempo para explicar adequadamente o problema, pois acredito que você não entendeu bem a arquitetura limpa de Martin e a MVVM.

A primeira coisa a observar é que o diagrama que você postou está incompleto. Ele mostra apenas "lógica de negócios", mas está faltando algum tipo de "orquestrador" que realmente faz as peças se moverem na ordem certa. insira a descrição da imagem aqui

O código do orquestrador seria tão simples quanto

string Request(string request) // returns response
{
    Controller.Run(data);
    Presenter.Run();
    return View.Run();
}

Acredito ter ouvido Martin falar sobre isso em uma de suas palestras sobre Arquitetura Limpa.

Outra coisa a salientar é que a observação de candied_orange sobre falta de ciclos está errada. Sim, o ciclo não existe (e não deveria) na arquitetura do código. Mas os ciclos entre instâncias de tempo de execução são comuns e geralmente levam a um design mais simples.

Esse é o caso no MVVM. No MVVM, o View depende do ViewModel, e o ViewModel usa eventos para notificar o View sobre suas alterações. Isso significa que, no design das classes, há apenas dependência das classes View e Model, mas durante o tempo de execução, há dependência cíclica entre as instâncias View e ViewModel. Por esse motivo, não há necessidade de orquestrador, pois o ViewModel fornecerá ao View uma maneira de descobrir quando se atualizar. É por isso que as "notificações" neste diagrama usam a linha "ondulada" e não a linha direta. Isso significa que o View observa alterações no ViewModel, não que o ViewModel dependa do View.

insira a descrição da imagem aqui

A coisa mais importante que você deve tirar da arquitetura limpa de Martin não é o design em si, mas como você lida com as dependências. Um dos pontos críticos que ele faz em suas palestras é que, quando há um limite, todas as dependências de código que cruzam esse limite o atravessam em uma única direção. No diagrama, esse limite é representado por linha dupla. E há muita inversão de dependência por meio de interfaces ( InputBoundary, OutputBoundarye DataAccessInterface) que corrigem a direção da dependência do código.

Em contraste, a ViewModelarquitetura limpa é simplesmente um DTO simples, sem lógica. Isso é óbvio por <DS>tag. E é por isso que orchestratoré necessário, pois Viewnão saberá quando executar sua lógica.

Se eu "achatasse" o diagrama em como ele será durante o tempo de execução, ele será assim:

insira a descrição da imagem aqui

Portanto, durante o tempo de execução, as dependências estão na direção "errada", mas tudo bem.

Eu recomendo assistir sua palestra sobre Arquitetura Limpa para entender melhor seu raciocínio.


O seu "orquestrador" não deve ligar para o apresentador. O Interact Case Case faz isso.
Candied_orange 19/10/19

@candied_orange É verdade que isso é um erro.
Euphoric

Obrigado pela resposta, é sempre bom ter algumas opiniões diferentes. Eu votei nas duas respostas de vocês. Algum de vocês sabe se Robert Martin tem uma base de código em algum lugar em que ele implementou uma forma de sua arquitetura? Eu olhei para o projeto FitNess, mas não conseguia ver a floresta para as árvores. Além disso, estou correto ao especular que, embora a imagem que publiquei seja o diagrama que o tio Bob sempre usa em suas palestras, na verdade é apenas um exemplo de como sua arquitetura PODE se parecer? Considerando que pode parecer muito diferente, desde que o fluxo de dependência esteja correto?
Fearnbuster 19/10/19

@ Learnbuster Para sua última pergunta, sim. A direção das dependências é mais importante que a estrutura. Acredito que "arquitetura limpa", "arquitetura Onion" e "arquitetura hexagonal" são realmente implementações da mesma idéia de "manter as dependências sob controle".
Euphoric

@Euphoric Honestamente, eu diria que esse é provavelmente o caso, porque em uma imagem diferente de seu livro (Figura 8.2 do capítulo 8), ele mostra uma arquitetura que parece diferente. Nesse diagrama, o Controlador é na verdade um intermediário entre o Interator e o Apresentador. Também não há limite de saída para o Interator; parece que o Interator recebe solicitações por meio de uma interface e, em seguida, retorna as respostas pela mesma interface (presumo que isso seja feito através de um simples valor de retorno de função, pois não consigo pensar em nenhum outro mecanismo que funcione dessa maneira).
Fearnbuster 19/10/19
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.