使用更简单的MVP改进Vaadin 4 Spring项目

我在当前项目中一直使用Vaadin 4 Spring库,这是非常愉快的体验。 但是,在项目中期,我的一位同事决定“提高可测试性” 。 尽管该项目已经尝试实现MVP模式,但此意图值得称赞(请查看本文以获得更多详细信息)。 他没有在这里和那里纠正错误,而是使用提供的MVP模块重构了整个代码库...恕我直言,这是一个巨大的错误。 在本文中,我将着重介绍在现有实现中令人烦恼的内容,以及它的替代解决方案。

现有的MVP实现由单个类组成 。 在这里,出于可读性目的而进行了删节:

publicabstractclassPresenter<VextendsView>{

    @Autowired
    privateSpringViewProviderviewProvider;

    @Autowired
    privateEventBuseventBus;

    @PostConstruct
    protectedvoidinit(){
        eventBus.subscribe(this);
    }

    publicVgetView(){
        Vresult=null;
        Class<?>clazz=getClass();
        if(clazz.isAnnotationPresent(VaadinPresenter.class)){
            VaadinPresentervp=clazz.getAnnotation(VaadinPresenter.class);
            result=(V)viewProvider.getView(vp.viewName());
        }
        returnresult;
    }

    // Other plumbing code
}

这门课很固执,有以下缺点:

  1. 它依赖于现场自动装配,这使得很难对Presenter类进行单元测试 作为证明,提供的测试类不是单元测试,而是集成测试
  2. 它仅依赖于组件扫描,这可以防止显式依赖项注入。
  3. 无论是否需要,它都会强制执行View接口。 不使用导航器时,它将强制执行空的enterView()方法。
  4. 这需要建立从视图中提供的视图的责任。
  5. 它通过使用@VaadinPresenter注释将PresenterView结合@VaadinPresenter ,防止单个Presenter处理不同的View实现。
  6. 它需要显式调用Presenterinit()方法,因为当子类有一个时,超类的@PostConstruct注释不会被调用。

我开发了一个替代类,试图解决前面的要点-而且也更简单:

publicabstractclassPresenter<T>{

    privatefinalTview;
    privatefinalEventBuseventBus;

    publicPresenter(Tview,EventBuseventBus){
        Assert.notNull(view);
        Assert.notNull(eventBus);
        this.view=view;
        this.eventBus=eventBus;
        eventBus.subscribe(this);
    }

    // Other plumbing code
}

此类使每个子类都易于单元测试,如以下代码片段所示:

publicclassFooViewextendsLabel{}

publicclassFooPresenterextendsPresenter<FooView>{

    publicFooPresenter(FooViewview,EventBuseventBus){
        super(view,eventBus);
    }

    @EventBusListenerMethod
    publicvoidonNewCaption(Stringcaption){
        getView().setCaption(caption);
    }
}

publicclassPresenterTest{

    privateFooPresenterpresenter;
    privateFooViewfooView;
    privateEventBuseventBus;

    @Before
    publicvoidsetUp(){
        fooView=newFooView();
        eventBus=mock(EventBus.class);
        presenter=newFooPresenter(fooView,eventBus);
    }

    @Test
    publicvoidshould_manage_underlying_view(){
        Stringmessage="anymessagecangohere";
        presenter.onNewCaption(message);
        assertEquals(message,fooView.getCaption());
    }
}

还可以使用显式依赖项注入来处理与初始类相同的集成测试:

publicclassExplicitPresenterextendsPresenter<FooView>{

    publicExplicitPresenter(FooViewview,EventBuseventBus){
        super(view,eventBus);
    }

    @EventBusListenerMethod
    publicvoidonNewCaption(Stringcaption){
        getView().setCaption(caption);
    }
}

@Configuration
@EnableVaadin
publicclassExplicitConfig{

    @Autowired
    privateEventBuseventBus;

    @Bean
    @UIScope
    publicFooViewfooView(){
        returnnewFooView();
    }

    @Bean
    @UIScope
    publicExplicitPresenterfooPresenter(){
        returnnewExplicitPresenter(fooView(),eventBus);
    }
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=ExplicitConfig.class)
@VaadinAppConfiguration
publicclassExplicitPresenterIT{

    @Autowired
    privateExplicitPresenterexplicitPresenter;

    @Autowired
    privateEventBuseventBus;

    @Test
    publicvoidshould_listen_to_message(){
        Stringmessage="message_from_explicit";
        eventBus.publish(this,message);
        assertEquals(message,explicitPresenter.getView().getCaption());
    }
}

最后但并非最不重要的一点是,如果您愿意,此替代方法还可以让您使用自动接线和组件扫描! 唯一的区别是,它强制执行构造函数自动装配而不是字段自动装配(在我看来,这算是一个加号,尽管有点冗长):

@UIScope
@VaadinComponent
publicclassFooViewextendsLabel{}

@UIScope
@VaadinComponent
publicclassAutowiredPresenterextendsPresenter<FooView>{

    @Autowired
    publicAutowiredPresenter(FooViewview,EventBuseventBus){
        super(view,eventBus);
    }

    @EventBusListenerMethod
    publicvoidonNewCaption(Stringcaption){
        getView().setCaption(caption);
    }
}

@ComponentScan
@EnableVaadin
publicclassScanConfig{}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=ScanConfig.class)
@VaadinAppConfiguration
publicclassAutowiredPresenterIT{

    @Autowired
    privateAutowiredPresenterautowiredPresenter;

    @Autowired
    privateEventBuseventBus;

    @Test
    publicvoidshould_listen_to_message(){
        Stringmessage="message_from_autowired";
        eventBus.publish(this,message);
        assertEquals(message,autowiredPresenter.getView().getCaption());
    }
}

好消息是,此模块现已成为Github上vaadin4spring项目的一部分。 如果您的Vaadin Spring应用程序需要MVP,只需单击即可!

翻译自: https://blog.frankel.ch/improving-the-vaadin-4-spring-project-with-a-simpler-mvp/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值