Eu usei MVP e MVC no passado, e prefiro o MVP, pois ele controla o fluxo de execução muito melhor na minha opinião.
Criei minha infraestrutura (classes de armazenamento de dados / repositório) e as utilizo sem problemas ao codificar dados de amostra, agora estou migrando para a GUI e preparando meu MVP.
Seção a
Vi o MVP usando a visualização como ponto de entrada, ou seja, no método construtor de visualizações, ele cria o apresentador, que por sua vez cria o modelo, conectando os eventos conforme necessário.
Eu também vi o apresentador como o ponto de entrada, onde uma visão, modelo e apresentador são criados; esse apresentador recebe uma visão e um objeto de modelo em seu construtor para conectar os eventos.
Como em 2, mas o modelo não é passado para o apresentador. Em vez disso, o modelo é uma classe estática na qual os métodos são chamados e as respostas retornadas diretamente.
Seção B
Em termos de manter a visão e o modelo sincronizados, eu já vi.
Sempre que um valor na visualização é alterado, ou seja,
TextChanged
evento em .Net / C #. Isso aciona umaDataChangedEvent
passagem pelo modelo, para mantê-lo sincronizado o tempo todo. E onde o modelo muda, ou seja, um evento em segundo plano que ele escuta, a visualização é atualizada com a mesma idéia de aumentar aDataChangedEvent
. Quando um usuário deseja confirmar alterações,SaveEvent
ele é acionado, passando para o modelo para salvar. Nesse caso, o modelo imita os dados da visualização e processa ações.Semelhante ao # b1, no entanto, a visualização não é sincronizada com o modelo o tempo todo. Em vez disso, quando o usuário deseja confirmar as alterações,
SaveEvent
é demitido e o apresentador pega os detalhes mais recentes e os passa para o modelo. nesse caso, o modelo não conhece os dados das visualizações até que seja necessário agir sobre ele; nesse caso, são transmitidos todos os detalhes necessários.
Seção C
Exibição de objetos de negócios na exibição, ou seja, um objeto (MyClass) não dados primitivos (int, double)
A visualização possui campos de propriedades para todos os dados que serão exibidos como objetos de domínio / negócios. Tal como
view.Animals
expõe umaIEnumerable<IAnimal>
propriedade, mesmo que a exibição as processe em Nós em um TreeView. Então, para o animal selecionado, ele seria expostoSelectedAnimal
comoIAnimal
propriedade.A exibição não tem conhecimento de objetos de domínio, ela expõe propriedades apenas para tipos de objetos incluídos primitivos / framework (.Net / Java). Nesse caso, o apresentador passará um objeto do adaptador para o objeto de domínio, e o adaptador converterá um determinado objeto de negócios nos controles visíveis na exibição. Nesse caso, o adaptador deve ter acesso aos controles reais na visualização, e não apenas qualquer visualização, tornando-se mais acoplado.
Seção D
Várias visualizações usadas para criar um único controle. ou seja, você tem uma visão complexa com um modelo simples, como salvar objetos de diferentes tipos. Você pode ter um sistema de menus ao lado a cada clique em um item, os controles apropriados são mostrados.
Você cria uma visão enorme, que contém todos os controles individuais expostos pela interface de visualizações.
Você tem várias visualizações. Você tem uma visão para o menu e um painel em branco. Essa visão cria as outras visões necessárias, mas não as exibe (visible = false); essa visão também implementa a interface para cada visão que ela contém (ou seja, visões filhas) para que possa ser exposta a um apresentador. O painel em branco é preenchido com outras visualizações (
Controls.Add(myview)
) e ((myview.visible = true
). Os eventos gerados nessas visualizações "filho" são tratados pela visualização pai, que por sua vez passa o evento para o apresentador e vice-versa para fornecer eventos de volta aos elementos filhos.Cada visualização, seja a pai principal ou a filha menor, é conectada a cada apresentador e modelo. Você pode literalmente soltar um controle de exibição em um formulário existente e ele terá a funcionalidade pronta, basta conectar o apresentador nos bastidores.
Seção E
Se tudo tiver uma interface, agora, com base em como o MVP é feito nos exemplos acima, afetará esta resposta, pois eles podem não ser compatíveis.
Tudo tem uma interface, o View, Presenter e Model. Cada uma delas obviamente tem uma implementação concreta. Mesmo se você tiver apenas uma visão concreta, modelo e apresentador.
A Vista e o Modelo têm uma interface. Isso permite que as visualizações e os modelos sejam diferentes. O apresentador cria / recebe objetos de visualização e modelo e serve apenas para transmitir mensagens entre eles.
Somente o View tem uma interface. O Modelo possui métodos estáticos e não é criado, portanto, não há necessidade de uma interface. Se você deseja um modelo diferente, o apresentador chama um conjunto diferente de métodos de classe estática. Sendo estático, o Modelo não tem link para o apresentador.
Pensamentos pessoais
De todas as diferentes variações que apresentei (a maioria provavelmente usei de alguma forma), das quais tenho certeza de que existem mais. Prefiro A3 como manter a lógica de negócios reutilizável fora do MVP, B2, para menos duplicação de dados e menos eventos sendo disparados. C1 por não adicionar em outra classe, certifique-se de colocar uma pequena quantidade de lógica não testável por unidade em uma exibição (como um objeto de domínio é visualizado), mas isso pode ser revisado por código ou simplesmente visualizado no aplicativo. Se a lógica fosse complexa, eu concordaria com uma classe de adaptador, mas não em todos os casos. Para a seção D, sinto que o D1 cria uma exibição muito grande pelo menos para um exemplo de menu. Eu usei D2 e D3 antes. O problema com o D2 é que você precisa escrever muito código para rotear eventos de e para o apresentador para a exibição filho correta e não é compatível com arrastar / soltar cada novo controle precisa de mais fiação para suportar o único apresentador. D3 é minha escolha preferida, mas adiciona ainda mais classes como apresentadores e modelos para lidar com a visualização, mesmo que a visualização seja muito simples ou não precise ser reutilizada. Eu acho que uma mistura de D2 e D3 é melhor com base nas circunstâncias. Quanto à seção E, acho que tudo que tem uma interface pode ser um exagero. Eu já faço isso para objetos de domínio / negócios e geralmente não vejo vantagem no "design" ao fazê-lo, mas ajuda a zombar de objetos em testes. Pessoalmente, eu consideraria o E2 uma solução clássica, embora tenha visto o E3 usado em 2 projetos nos quais trabalhei anteriormente. Eu acho que uma mistura de D2 e D3 é melhor com base nas circunstâncias. Quanto à seção E, acho que tudo que tem uma interface pode ser um exagero. Eu já faço isso para objetos de domínio / negócios e geralmente não vejo vantagem no "design" ao fazê-lo, mas ajuda a zombar de objetos em testes. Pessoalmente, eu consideraria o E2 uma solução clássica, embora tenha visto o E3 usado em 2 projetos nos quais trabalhei anteriormente. Eu acho que uma mistura de D2 e D3 é melhor com base nas circunstâncias. Quanto à seção E, acho que tudo que tem uma interface pode ser um exagero. Eu já faço isso para objetos de domínio / negócios e geralmente não vejo vantagem no "design" ao fazê-lo, mas ajuda a zombar de objetos em testes. Pessoalmente, eu consideraria o E2 uma solução clássica, embora tenha visto o E3 usado em 2 projetos nos quais trabalhei anteriormente.
Questão
Estou implementando o MVP corretamente? Existe uma maneira correta de fazer isso?
Eu li o trabalho de Martin Fowler que tem variações, e eu lembro que quando comecei a MVC, entendi o conceito, mas não conseguia descobrir onde é o ponto de entrada, tudo tem sua própria função, mas o que controla e cria o original conjunto de objetos MVC.