GWT Model-View-Presenter是用于大规模应用程序开发的设计模式。 它源于MVC,它在视图和逻辑之间进行划分,并有助于创建结构良好,易于测试的代码。 为了帮助像我这样的懒惰开发人员,我研究了如何减少使用声明式UI时要编写的类和接口的数量。

经典MVP

您知道如何在Facebook中发布链接吗? –最近,我不得不为一个小GWT旅行应用程序创建此功能。

因此,您可以输入一个URL,然后将其提取并解析。 您可以从页面中选择图像之一,查看文本,最后存储链接。
现在如何在MVP中正确设置此设置? –首先,创建一个类似于视图的抽象接口:

interface Display {HasValue<String> getUrl();void showResult();HasValue<String> getName();HasClickHandlers getPrevImage();HasClickHandlers getNextImage();void setImageUrl(String url);HasHTML getText();HasClickHandlers getSave();
}

它利用GWT组件实现的接口来提供对其状态和功能的某些访问。 在测试期间,您无需参考GWT内部即可轻松实现此接口。 同样,可以在不影响更深层逻辑的情况下更改视图实现。
该实现非常简单,此处显示了声明的UI字段:

class LinkView implements Display@UiField TextBox url;@UiField Label name;@UiField VerticalPanel result;@UiField Anchor prevImage;@UiField Anchor nextImage;@UiField Image image;@UiField HTML text;@UiField Button save;public HasValue<String> getUrl() {return url;}public void showResult() {result.setVisible(true);}// ... and so on ...
}

然后,演示者使用接口访问视图,按照惯例,该接口写在presenter类中:

class LinkPresenterinterface Display {...};public LinkPresenter(final Display display) {display.getUrl().addValueChangeHandler(new ValueChangeHandler<String>() {@Overridepublic void onValueChange(ValueChangeEvent<String> event) {Page page = parseLink(display.getUrl().getValue());display.getName().setValue(page.getTitle());// ...display.showResult();}});}// ... and so on ...
}

因此,我们在这里:使用MVP,您可以很好地构造代码并使代码易于阅读。

简化

收益是: 每个屏幕或组件三种类型 。 每当重新定义UI时,三个文件都将更改。 未将ui.xml文件计入视图声明。 对于像我这样的懒人来说,这些太多了。 而且,如果您查看视图实现,很明显如何简化它:
使用视图声明(* .ui.xml)作为视图,并将ui元素直接注入到presenter中:

class LinkPresenter@UiField HasValue<String> url;@UiField HasValue<String> name;@UiField VerticalPanel result;@UiField HasClickHandlers prevImage;@UiField HasClickHandlers nextImage;@UiField HasUrl image;@UiField HasHTML text;@UiField HasClickHandlers save;public LinkPresenter(final Display display) {url.addValueChangeHandler(new ValueChangeHandler<String>() {@Overridepublic void onValueChange(ValueChangeEvent<String> event) {Page page = parseLink(url.getValue());name.setValue(page.getTitle());// ...result.setVisible(true);}});}// ... and so on ...
}

由于可以使用它们的接口声明注入的元素,因此此演示者具有成熟的MVP演示者的许多优点:您可以通过设置实现组件来对其进行测试(请参见下文),并且可以轻松地更改视图实现。
但是现在,您将所有这些都放在一个类和一个view.ui.xml文件中,并且可以更简单地应用结构更改。

使UI元素抽象

TextBox实现HasValue <String>。 这很简单。 但是,不能通过接口访问的ui元素的属性呢? 您可能已经认识到的一个示例是上述代码中的VerticalPanel命名结果result及其方法setVisible(),不幸的是,该方法在UiObject基类中实现。 因此,没有可用的接口,例如。 在测试时实施。 为了能够切换视图实现,最好注入ComplexPanel,但即使在测试时也无法实例化。

例如,在这种情况下,唯一的解决方法是创建一个新接口

interface Visible {void setVisible(boolean visible);boolean isVisible();
}

和子类化有趣的UI组件,实现相关的接口:

package de.joergviola.gwt.tools;
class VisibleVerticalPanel extends VerticalPanel implements Visible {}

这似乎是乏味和次优的。 但是,只能像上述成熟的MVP中那样仅针对每个组件而不是针对每个视图进行操作。
等待-如何在UiBuilder模板中使用自制组件? –很简单:

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:t="urn:import:de.joergviola.gwt.tools"><g:VerticalPanel width="100%"><g:TextBox styleName="big" ui:field="url" width="90%"/><t:VisibleVerticalPanel ui:field="result"visible="false"  width="100%"></t:VisibleVerticalPanel></g:VerticalPanel>
</ui:UiBinder>

声明处理程序

声明(click-)处理程序的标准方法非常方便:

@UiHandler("login")public void login(ClickEvent event) {srv.login(username.getValue(), password.getValue());}

在简化的MVP方法中,此代码将驻留在演示者中。 但是ClickEvent参数是View组件,可以例如。 不能在运行时实例化。 另一方面,由于UiBuilder需要Event参数,因此无法从签名中将其删除。

因此,不幸的是,您必须坚持手动注册ClickHandlers(因为无论如何都必须执行完整的MVP):

public initWidget() {...login.addClickHandler(new ClickHandler() {@Overridepublic void onClick(ClickEvent event) {login();}});...
}public void login(ClickEvent event) {srv.login(username.getValue(), password.getValue());
}

测试中
引入MVP时,使您的应用程序可测试是主要目标之一。
GwtTestCase能够在容器环境中执行测试,但需要一些启动时间。 在TDD中,希望有一个运行速度非常快的测试,可以在每次更改后应用它而不会丢失上下文。 因此,MVP旨在能够在标准JVM中测试所有代码。 在标准MVP中,您将创建视图接口的实现。 在这种简化方法中,只需在组件接口级别上创建实现即可,如下所示:

class Value<T> implements HasValue<T> {private T value;List<ValueChangeHandler<T>> handlers = new ArrayList<ValueChangeHandler<T>>();@Overridepublic HandlerRegistration addValueChangeHandler(ValueChangeHandler<T> handler) {handlers.add(handler);return null;}@Overridepublic void fireEvent(GwtEvent<?> event) {for (ValueChangeHandler<T> handler : handlers) {handler.onValueChange((ValueChangeEvent) event);}}@Overridepublic T getValue() {return value;}@Overridepublic void setValue(T value) {this.value = value;}@Overridepublic void setValue(T value, boolean fireEvents) {if (fireEvents)ValueChangeEvent.fire(this, value);setValue(value);}}

与往常一样,您必须将此组件注入到被测演示者中。 尽管从原则上讲,您可以为组件创建一个设置器,但我仍然遵循通常的技巧来使组件受到包保护,将测试与演示者放入同一包中(但当然是不同的项目文件夹),然后直接设置组件。

你赢了什么?

您得到的代码结构像完整的MVP一样干净,只需要更少的类和样板代码。
在某些情况下,组件及其接口需要实用程序类,但是随着时间的流逝,您将构建一个真正易于理解,测试和扩展的环境。

我很好奇:告诉我您的经历!

参考: GWT MVP从我们的JCG合作伙伴那里变得简单   Joerg Viola在Joerg Viola博客上 。

翻译自: https://www.javacodegeeks.com/2012/02/gwt-mvp-made-simple.html

GWT MVP变得简单相关推荐

  1. gwt的mvp模式_GWT MVP变得简单

    gwt的mvp模式 GWT Model-View-Presenter是用于大规模应用程序开发的设计模式. 它源于MVC,它在视图和逻辑之间进行划分,并有助于创建结构良好,易于测试的代码. 为了帮助像我 ...

  2. Skaffold:让K8S开发工作变得简单

    Skaffold:让K8S开发工作变得简单 本文介绍在开发过程中,Skaffold自动化build和deploy应用到K8S集群. Skaffold是由Google发布的命令行工具,专注于促进K8S应 ...

  3. openshift_云上的播放框架变得简单:Openshift模块

    openshift 仅仅几年前,找到一个负担得起的Java Web应用程序托管解决方案是一项艰巨的任务,而寻找免费的托管解决方案是一项不可能的任务. 更不用说考虑自动缩放,单命令部署,持续集成等问题了 ...

  4. 云上的播放框架变得简单:Openshift模块

    仅仅几年前,找到一个负担得起的Java Web应用程序托管解决方案是一项艰巨的任务,而寻找免费的托管解决方案是一项不可能的任务. 更不用说甚至考虑自动缩放,单命令部署,持续集成等事情,这都是科幻小说. ...

  5. 9切换中文mac_超详细的Mac重装系统教程!让重装系统变得简单起来!

    mac电脑该怎么重装系统?苹果电脑在长时间使用后,系统可能会变得比较慢,另外各种缓存垃圾也会越堆越多,影响电脑的反应速度.mac OS系统是苹果电脑独有的操作系统,重装mac系统过程和Win系统完全不 ...

  6. 蒸汽朋克简单图形免扣PNG素材,让设计艺术变得简单

    蒸汽波艺术风格融入到当今的设计中是非常抢眼的,例如淘宝造物节也大量使用蒸汽波风格等. 蒸汽波的风格设计时尚新潮元素众多,可以迅速吸引用户眼球,在设计中做蒸汽波风格时也要切记在运用颜色和元素摆放时多考虑 ...

  7. 让Netty入门变得简单

    让Netty入门变得简单 https://mp.weixin.qq.com/s/MBnbLmCmFJo0QK9WNwXrXQ 如果先启动nettyClient就不会有nettyServer输出了: p ...

  8. 2022餐饮加盟3大核心,让赚钱变得简单

    根据2022餐饮加盟项目排行来看,20-30万投资金额是投资者最理想的区间,从餐饮品类来看休闲饮品和小吃快餐是最为热门的品类.休闲饮品最受资本青睐是因为深受年轻人喜欢,年轻人是消费的主力军,小吃快餐因 ...

  9. 个人电脑秒变服务器 简单几步,你的电脑也可以成为服务器 (内网穿透)

    个人电脑秒变服务器 简单几步,你的电脑也可以作为服务器 简述 解决方法 前期准备 使用步骤 简述 前段时间学校实训遇到一个问题,运行在个人电脑的系统需要通过手机进行访问,当时在实训时采用的解决方式是将 ...

最新文章

  1. 小程序的ui应该怎么设计?
  2. 这位年仅27岁的阿联酋人工智能部长,竟计划2117年火星造城,真是有钱帅气又任性!
  3. 反转链表:输入一个链表的头结点,反转该链表并输出反转后的链表的头结点。...
  4. texlive2015+texstudio
  5. HBase 6、用Phoenix Java api操作HBase
  6. PP: 混合生产方式(MTO与MTS为例)
  7. 如何理解 JAVA 中的 volatile 关键字
  8. QT的QMutableMapIterator类的使用
  9. LeetCode 1136. 平行课程(拓扑排序)
  10. 内存缓存LruCache实现原理
  11. 推荐一篇关于多租户Multi-Tenant数据架构的文章
  12. 组合枚举——妖梦拼木棒(洛谷 P3799)
  13. 计算机系徽文案例,信息技术系——系徽征集令,重磅发布!
  14. LFSR:线性反馈移位寄存器及其应用
  15. eclipse adt bundle不显示Android SDK菜单
  16. Golang + selenium 设置无头浏览器模式
  17. java中抽象类继承抽象类_邮政编码作为Java中抽象类的示例
  18. pda通用扫描app_手持终端PDA盘点机盘点软件盘点APP
  19. Travis CI(持续集成)
  20. 记一次被QQ邮箱钓鱼邮件事件

热门文章

  1. 双指针:88. 合并两个有序数组
  2. buildpack_使用Buildpack容器化Spring Boot应用程序
  3. mockito接口没法赋值_Mockito:无法实例化@InjectMocks字段:类型是接口
  4. zing jvm_Zing加快了JVM应用程序的预热
  5. 气味识别应用_解决气味
  6. java私有属性和私有方法_Java 9中什么是私有的?
  7. 线程同步 线程安全_同步装饰器来替换线程安全类
  8. junit数据驱动测试_使用Junit和Easytest进行数据驱动的测试
  9. jdbc mysql驱动_MySQL JDBC驱动程序如何处理准备好的语句
  10. hamcrest_重新设计Hamcrest