我想创建以下简单的MVP架构:
查看类似于vaadin布局,组件和样式的类。非功能性。视图应与当前的ViewScope / SessionScope绑定,因此我使用https://github.com/peholmst/vaadin4spring的@UIScope
演示者应该注入视图,在视图组件上注册侦听器,处理用户输入并委托模型服务
问题:当我将视图注入演示者时,视图会重新创建,因此演示者和视图不在同一范围内。所以绑定不起作用。 我可以改变什么来实现上述设计?
@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
}
}
答案 0 :(得分:5)
也许像
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;
}
}
修改强>
您可以解耦添加配置界面,但会增加一些复杂性,例如
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");
}
}
答案 1 :(得分:1)
我在当前的项目中遇到了类似的问题,我现在以下列方式解决了这个问题:
@VaadinUI
public class MainUI extends UI {
@Autowired
private MainView mainView;
@Autowired
private MainPresenter mainPresenter;
@Autowired
private Test1Presenter test1Presenter;
@Autowired
private Test2Presenter test2Presenter;
@Override
protected void init(final VaadinRequest vaadinRequest) {
setContent(this.mainView);
}
}
@Component
@Scope("ui")
@VaadinView(name = "MainView")
public class MainView extends CustomComponent {
private static final Logger LOGGER = LoggerFactory.getLogger(MainView.class);
private TabSheet tabSheet;
@Autowired
private Test1Tab test1Tab;
@Autowired
private Test2Tab test2Tab;
@PostConstruct
private void init() {
LOGGER.debug("MainView - Method init - Test1Tab: " + this.test1Tab);
this.tabSheet = new TabSheet();
this.tabSheet.addTab(this.test1Tab);
this.tabSheet.addTab(this.test2Tab);
setCompositionRoot(this.tabSheet);
}
public TabSheet getTabSheet() {
return this.tabSheet;
}
public Test1Tab getTest1Tab() {
return this.test1Tab;
}
public Test2Tab getTest2Tab() {
return this.test2Tab;
}
}
@Controller
@Scope("ui")
// Implementing Serializable was necessary to remove the warning "Storing
// non-serializable bean [...] with name [...] in UI space [...]".
public class MainPresenter implements Serializable {
@Autowired
private MainModel model;
@Autowired
private MainView view;
@PostConstruct
private void init() {
// ...
}
}
@Component
@Scope("ui")
@VaadinView(name = "Test1Tab")
public class AlarmsTab extends VerticalLayout {
private final Button test1Button = new Button("Test 1");
private final Button test2Button = new Button("Test 2");
public Test1Tab() {
setCaption("Test1");
setMargin(true);
setSpacing(true);
addComponent(this.test1Button);
addComponent(this.test2Button);
}
public Button getTest1Button() {
return this.test1Button;
}
public Button getTest2Button() {
return this.test2Button;
}
}
@Controller
@Scope("ui")
public class Test1Presenter implements Serializable {
private static final Logger LOGGER = LoggerFactory.getLogger(Test1Presenter.class);
@Autowired
private MainModel model;
@Autowired
private Test1Tab view;
@PostConstruct
private void init() {
LOGGER.debug("Test1Presenter - Method init - Test1Tab: " + this.view);
this.view.getTest1Button().addClickListener(new ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
// ...
}
});
this.view.getTest2Button().addClickListener(new ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
// ...
}
});
}
}
这种方法有效,但我不确定我是否正确使用了范围(视图和演示者都使用@Scope(“ui”)注释)。
对此有何评论?