De acordo com a descrição do MVP de Martin Fowler ( http://martinfowler.com/eaaDev/uiArchs.html )
Da parte View do MVC, Fowler diz:
O primeiro elemento do Potel é tratar a visualização como uma estrutura de widgets, widgets que correspondem aos controles do modelo Forms and Controls e remover qualquer separação de visualização / controlador. A visão do MVP é uma estrutura desses widgets. Ele não contém nenhum comportamento que descreve como os widgets reagem à interação do usuário .
(Negrito ênfase minha)
Então do apresentador:
A reação ativa ao usuário age em um objeto apresentador separado. Os manipuladores fundamentais para gestos do usuário ainda existem nos widgets, mas esses manipuladores apenas passam o controle para o apresentador .
O apresentador decide como reagir ao evento. Potel discute essa interação principalmente em termos de ações no modelo, o que é feito por um sistema de comandos e seleções. Uma coisa útil a destacar aqui é a abordagem de empacotar todas as edições do modelo em um comando - isso fornece uma boa base para fornecer o comportamento de desfazer / refazer.
(Novamente, ênfase em negrito)
Portanto, de acordo com as diretrizes da Fowler, sua exibição não deve ser responsável por nenhum comportamento em resposta ao evento do botão; que inclui a criação de uma instância de UserInfo
. A responsabilidade de decidir criar um objeto pertence ao método Presenter para o qual o evento da interface do usuário é encaminhado.
No entanto, também se pode argumentar que o manipulador de eventos de botão do View também não deve ser responsável por transmitir o conteúdo do textView
mesmo, pois o View deve apenas encaminhar o evento button para o Presenter e nada mais.
Com o MVP, é comum a exibição implementar uma interface que o apresentador pode usar para coletar dados diretamente da exibição (enquanto garante que o apresentador ainda seja independente da própria exibição). Como o UserInfo é um POJO simples, pode ser válido que a exibição exponha um getter para a UserInfo que o Presenter possa selecionar da View por meio de uma interface.
// The view would implement IView
public interface IView {
public UserInfo GetUserInfo();
}
// Presenter
public class AddUserPresenter {
private IView addUserView;
public void SetView(IView view) {
addUserView = view
}
public void onSomethingClicked() {
UserInfo userInfo = addUserView.GetUserInfo();
// etc.
}
}
Como isso é diferente de passar o UserInfo
diretamente para a exibição usando o manipulador de eventos? A principal diferença é que o apresentador ainda é o responsável final pela lógica que causa UserInfo
a criação de um objeto. isto é, o evento chegou ao apresentador antes da criação do UserInfo
, permitindo ao apresentador tomar a decisão.
Imagine um cenário em que você tivesse lógica de apresentador em que não desejasse que isso UserInfo
fosse criado com base em algum estado da exibição. Por exemplo, se o usuário não marcou uma caixa de seleção na exibição, ou você teve uma verificação de validação em algum campo a ser adicionado à UserInfo que falhou - seu apresentador pode conter uma verificação adicional antes de ligar GetUserInfo
- ou seja
private boolean IsUsernameValid() {
String username = addUserView.GetUsername();
return (username != null && !username.isEmpty());
}
public void onSomethingClicked() {
if (IsUsernameValid()) {
UserInfo userInfo = addUserView.GetUserInfo();
// etc.
}
}
Essa lógica permanece dentro do apresentador e não precisa ser adicionada à exibição. Se a visão fosse responsável pela chamada GetUserInfo()
, ela também seria responsável por qualquer lógica que envolvesse seu uso; que é o que o padrão MVP está tentando evitar.
Portanto, embora o método que cria que UserInfo
possa existir fisicamente na classe View, nunca seja chamado a partir da classe View, apenas a partir do Presenter.
Obviamente, se a criação das UserInfo
finalizações exigir verificações adicionais em relação ao conteúdo dos widgets de entrada do usuário (por exemplo, conversão de string, validação etc.), seria melhor expor getters individuais para essas coisas, para que a validação / conversão de string possa demorar coloque dentro do Presenter - e, em seguida, o apresentador cria o seu UserInfo
.
No geral, seu principal objetivo em relação à separação entre o Presenter / View é garantir que você nunca precise escrever lógica na exibição. Se você precisar adicionar uma if
declaração por qualquer motivo (mesmo que seja uma if
declaração sobre o estado de uma propriedade do widget - marcando uma caixa de texto vazia ou um booleano para uma caixa de seleção), ela pertence ao apresentador.
onSomethingClicked()
, portanto, quando o usuário clica em "alguma coisa", o View chamapresenter.onSomethingClicked()
? Ou meus métodos de apresentador devem ser nomeados como as ações pretendidas, no meu casoaddUser()
?