I'd like to create the following simple MVP architecture:
View classes that are simly the vaadin layout, components, styles. nonfunctional. The views should be tied to the current ViewScope/SessionScope, therefore I use @UIScope
of https://github.com/peholmst/vaadin4spring
Presenters should have the view injected, register listeners on the view components, handle user input and delegate to the model services
Problem: when I inject the view into the presenter, the view is recreated, thus presenter and view are not in the same scope. So the binding will not work. What can I change to achieve the design described above?
@VaadinComponent
@UIScope
public class LoginView {
//form fields, buttons
}
@Controller
public class LoginPresenter implements ClickListener {
@Autowired
private LoginView view;
@PostConstruct
public void bind() {
view.getLoginButton().addClickListener(this);
}
@Override
public void buttonClick(ClickEvent event) {
//validate input and login
}
}
Maybe something like
public class LoginView {
@Autowired
public void initPresenter(LoginPresenter loginPresenter) {
loginPresenter.setLoginView(this);
loginPresenter.bind();
}
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class LoginPresenter {
private LoginView loginView;
public void bind() {
// ...
}
public LoginView getLoginView() {
return loginView;
}
public void setLoginView(LoginView loginView) {
this.loginView = loginView;
}
}
Edit
You can decouple adding a configuration interface but adds some complexity, for example
public interface View {
}
public interface Presenter {
void setView(View view);
void bind();
}
public interface ViewManager {
void configure(View view);
}
public class ViewSupport implements View {
@Autowired
private ViewManager viewManager;
@PostConstruct
public void init() {
viewManager.configure(this);
}
}
/**
* ViewManager that configure Presenters following
* the naming convention XXView->XXPresenter
*/
public class DefaultViewManager implements ViewManager {
@Autowired
private ApplicationContext applicationContext;
@Override
public void configure(View view) {
Presenter p = (Presenter) applicationContext.getBean(getPresenterName(view.getClass()));
p.setView(view);
p.bind();
}
protected String getPresenterName(Class<?> clazz) {
return StringUtils.uncapitalize(clazz.getSimpleName()).replace("View", "Presenter");
}
}