我们在Mendix上有时候需要实现称为回调(Callback)的一种设计模式。为了帮助理解 Callback 试图解决的问题,通过以下示例项目管理的应用程序来说明我们的使用场景。

与大多数项目管理应用程序一样,我们的示例应用程序允许经理将人员分配到不同的项目。我们的工作,是实现从项目中重新分配/删除人员的功能。

如您所见,这两个操作(重新分配和删除)都需要确认。只有在用户点击确认操作后,人员才会从现有项目中删除,或重新分配到另一个项目。然后更新分配到项目的人数。这是软件开发中非常常见的场景。通常,操作不能立即执行,即同步执行(比如项目人数的更新)。它必须等待另一个操作(人员重新分配/删除后)完成才能执行。此类异步操作的一些示例是:用户输入、IO 操作、网络请求、后台作业等。

在 Mendix 中实现此功能的最简单方法,是拥有两个独立的几乎相同的确认对话框和操作按钮,每个按钮调用不同的微流实现我们的需求。

但是,这会在代码库中引入重复。更糟糕的是,如果我们需要添加新操作,那么我们又需要制作另一个新的对话框副本(我们擅长做CV工程师,但这并不体现工程师价值)。

我们尝试做一点设计的工作。消除冗余模块的更好方法是使用枚举属性来表示我们想要执行的操作。然后我们可以用一个对话框和一个微流来实现这两个过程。我们可以使用条件可见性在 UI 中显示正确的信息,并使用条件选择来触发微流中的正确逻辑。

我们已经有了基础的思路,但添加另一个操作需要添加另一个枚举选项和另一个从条件选择中分离出来的微流。在设计上,这也不太理想,如果微流,或者其他的逻辑功能,由第三方(例如应用商店模块)提供时,那么你会发现问题越来越复杂。因为确认逻辑与操作逻辑(remove/reassign)耦合在一起,这种设计也打破了单一功能原则(Single Responsibility Principle,简称SRP,一种面向对象设计的原则)。

理想的解决方案将允许我们定义需要在确认过程结束时执行的操作逻辑,而无需更改任何确认过程代码,尤其是确认对话框。回调模式就能够让我们做到这一点。

回调

回调,Callback或者叫做Call after,是将方法作为参数传递给其它方法,预计在特定时间回调(执行)作为参数的方法。

我们首先看看如何在“经典”编程语言中实现这种模式。这是一个非常基本的 JavaScript 回调示例。

// third_party_library.js
function executeWithConfirmation(message, callback) {showConfirmationDialog(message);confirmBtn.addEventListener("click", callback);
}// bussiness_logic.js
function removeFromProject() {//从项目中删除人员的逻辑
}// index.js
removeBtn.addEventListener("click", function () {executeWithConfirmation("Are you sure?", removeFromProject); // 传入需要执行的方法
});

从示例中可以看出,回调的好处是third_party_library.js代码不知道或不关心回调在做什么。这使得即使在不同的文件中也可以定义回调函数。最重要的是,更改回调以适应不同的场景非常简单。如果third_party_library.js代码是我们不想编辑的库的一部分,则第二部分特别有用。实质上,回调允许我们在不更改其源代码的情况下更改库的部分行为。

Mendix 中的回调

JavaScript 示例简单而优雅。但是,如果您尝试将上述代码移植到 Mendix,您会发现需要解决如下的问题:Mendix 对函数(即微流指针)没有很好的支持换句话说,在 Mendix 中,很难传递一个微流以供稍后调用。有几种方法可以解决这个问题。我将列出三个最常见的方法:

  • 将微流名称作为字符串传递

这在CommunityCommom模块中可以找到一个有用的Java方法(Java Action),例如RunMicroflowAsyncInQueue。但是这个方法有三个主要缺点,所有这些稍有不慎,就会导致运行时失败:1)在执行操作之前不会检查微流名称。如果名称中有拼写错误,则调用将在运行时失败。2)如果微流或模块的名称发生变化,或者微流被删除,项目仍然可以编译,但在运行时调用将失败。3)如果改变回调微流的参数个数和类型,代码运行时会失败。

  • 将微流作为模型反射对象传递

模型反射模块使 Mendix 项目中的所有微流都可用作微流实体的对象。如果需要在 UI 中配置微流,这将特别有用。例如在 Process Queue 和 Excel 导入/导出模块中进行配置。但是这种方法只比将微流名称作为字符串传递稍微好一点,因为它只解决了上面提到的第一个问题,即微流名称中的意外拼写错误。重命名或删除微流或更改参数仍会导致运行时失败。

  • 将微流作为Java方法(Java Action)参数传递

在 7.18 版本中,Mendix 为Java方法引入了 Microflow 参数的概念。如果微流移动到另一个模块、重命名或删除,我们会收到编译错误。这是好事。但是,没有检查参数的数量和类型,这意味着在那里所做的任何更改在运行时仍会导致错误。

如您所见,上述所有选项都有缺点。但是,以下的概念可以让您知道使用事件处理(Event Handler)来解决我们的问题,这里简单阐述思路:

“我们首先定义实体的层次结构,其中每个特化(Specialization)都有为某个对象事件配置的不同事件微流,例如在提交之前。然后通过传递一个特化实体的实例,我们在某种意义上传递了一个微流指针。要触发微流,我们只需要触发相应的事件,例如通过提交对象。”

现在我们已经解决了如何在 Mendix 中传递微流指针的问题,让我们回到示例应用程序,看看我们如何实现回调模式。

示例应用回调实现

这是 Mendix 中使用回调的新流程的抽象视图。

首先,我们需要定义一个实体层次结构。我们定义了一个名为PersonListOperation的“抽象”实体,它有两个专门化ReassignOperation和 RemoveOperation。

每个特化都为提交前事件配置了不同的微流。请注意,我们如何使用 PersonListOperation实体来存储必要的信息,例如项目、人员列表、字符串标签等。特化实体可以存储仅与该特定回调相关的信息。例如, ReassignOperation 和人们将被重新分配到的新项目有一个关联关系。

当用户单击其中一个按钮时,我们会创建相应的回调对象:

对于这两种情况,我们都使用基于泛化实体PersonListOperation的单个确认对话框:

最后,单击 Yes 我们执行以下微流,它通过提交帮助程序 NPE 对象来调用正确的回调微流。

示例已经完成,如果您想研究更深入,可以在Github上找到示例项目的完整源代码。https://github.com/gajduk/Mendix-Design-Patterns

小结

通过使用回调模式,开发人员可以编写运行可维护和可扩展的异步进程的模块。使用这些模块的任何人都可以轻松定义要在异步操作完成后执行的自定义逻辑,而无需更改模块代码。由于使用了事件处理程序,如果回调微流被删除或参数不正确,这将在编译时而不是在运行时被捕获,这要归功于事件处理程序的使用。

最后 - 从纳流调用微流

事件处理程序(Event Handler)为我们提供了一种无需显式执行即可传递和调用微流的方法。这在不可能显式调用微流的情况下派上用场,尤其是在纳流的上下文中。您可能认为这首先违背了优先使用 nanoflow 作为在客户端运行逻辑的方式。这个想法是对的,如果我们可以更好设计客户端和服务端的逻辑分离时,应该坚持这种设计方式。而文章仍然认为,在许多情况下,在向服务器发送请求以运行微流之前,您可以在客户端完成一些检查/验证。在这种情况下,只有在所有检查都通过时才会调用微流。这允许您使用 nanoflow 向用户提供快速反馈并节省服务器上的一些处理时间,同时仍将复杂逻辑委派为 microflow 的一部分来执行。

更多信息,请访问以下链接:

Mendix官网:低代码应用开发平台 - 快速高效地构建应用 | Mendix

Mendix中国论坛:Mendix开发者论坛-加入Mendix开发者论坛,一起引领创新。

Mendix行业解决方案:Low-Code Solution Gallery | Customizable Solutions For Every Industry

Mendix平台指南:Low-Code Application Development Platform Evaluation Guide | Mendix

Mendix动画展示:Application Development Demos – Mendix Low-Code Platform

感谢阅读!

Mendix设计模式 - 回调相关推荐

  1. Java设计模式-回调函数和观察者模式

    Android的框架中有非常多的地方使用了回调的模式,例如Activity的生命周期,按钮的点击事件等. 下面是回调的基本模型: public class A {private CallBack ca ...

  2. 设计模式整理的好的文章2

    <DT><H3 ADD_DATE="1516155344" LAST_MODIFIED="1516698886">责任链模式</H ...

  3. Android Tips - 填坑手册

    转载自汤奇V分享的Android-Tips 学习 Android 至今,大大小小的坑没少踩,庆幸的是,在强大的搜索引擎与无私奉献的人们的帮助下,我遇到的坑都顺利地被填平了. 为了便于日后遇到同样的问题 ...

  4. android 开发从入门到精通

    Android-Tips This is an awesome list of tips for android. If you are a beginner, this list will be t ...

  5. Android Tips - 专业填坑手册

    Android-Tips 学习 Android 至今,大大小小的坑没少踩,庆幸的是,在强大的搜索引擎与无私奉献的人们的帮助下,我遇到的坑都顺利地被填平了. 为了便于日后遇到同样的问题时,能免于再次搜索 ...

  6. 观察者设计模式二:回调函数

    在上篇博客中具体介绍了观察者设计模式在异步短信发送中的应用场景,但是,在具体的业务中短息发送使用那种方式则会令代码很不友好: 这里我使用的是回调函数的方式来实现这个业务需求: 在具体的业务场景中,我们 ...

  7. Java设计模式之回调函数

    严格来说,回调函数并不属于23种设计模式中的任何一种.但是,回调函数在微服务中的使用越来越多,所以今天再来总结复习一下. 回调的意义在于,通过在其他对象中调用自身类中定义的函数,达到一定的目的(常见于 ...

  8. 设计模式之Future模式——提交任务后立即得到一个Future对象,后面利用该对象得到具体的执行结果。加上回调功能,任务执行结束通知调用者或直接回调相应方法

    1. Future模式的实现逻辑 1.1 在具体实现之前,我们先将Future模式的实现逻辑和流程理清楚,然后编写代码. 1.2 以甜品店买奶茶为例.第一步:得先有服务员:第二步:我们提交一个奶茶订单 ...

  9. GOF23设计模式(创建型模式)单例模式

    目录: 一:单例模式的核心作用.常见应用场景 二:五种单例模式及其实现 三:关于反射和反序列化破解单例模式的漏洞,以及相应的解决方案 四:测试五种单例模式的效率 一:核心作用及常见应用场景: 核心作用 ...

最新文章

  1. FillMode详解
  2. java returnaddress_Java虚拟机规范】Java SE 7虚拟机结构
  3. 基于组件的案例:购物车
  4. Boost::Exception提供的各种常用 error_info typedef的预期用途的测试
  5. 【Linux导论】Linux引导流程(The Boot Process)
  6. java 中break如何跳出多层循环(包含二层循环)
  7. ICCV 2019 | 上海交大MVIG团队提出InstaBoost,换个dataloader函数, COCO提升3mAP
  8. C语言的inline
  9. spark中dataframe解析_Spark 结构流处理介绍和入门教程
  10. linux spidev 应用_嵌入式Linux设备树语法总结
  11. 缺失值填充2——python 热卡填充(Hot deck imputation)、冷卡填充(Cold deck imputation)
  12. 【LeetCode】【HOT】297. 二叉树的序列化与反序列化(BFS)
  13. 这届 Windows 不行,是因为微软不卖“软件”改卖“服务”?
  14. Android Layout标签之-viewStub,requestFocus,merge,include
  15. python—try-expect-else-finally的使用
  16. 电脑主机服务器中毒文件怎么恢复出厂设置,服务器中毒了 物理文件怎么拷贝呢 以及如何恢复数据呢...
  17. 月中工作总结_在全职工作的9个月中,我是如何从新手转到软件工程师的
  18. word与EndNote管理文献~引文格式问题
  19. 圣杯布局原来这么简单!!
  20. Process finished with exit code 1Class not found:

热门文章

  1. WMS、WFS、WMTS服务接口说明
  2. 三角分解、满秩分解、Schur分解与奇异值分解一网打尽
  3. 哈工大计算机学院2017,2017年哈工大计算机学院接收推免生公告
  4. 【研究生版】《漫漫邮子路(五)--我的研究生之路--吕林输》
  5. 论如何在DEV C++中修改窗口的图标(包括任务栏图标)
  6. emoji iphone android,Emoji Android to iphone
  7. 基于 VANET 的车辆网络通信系统的 Matlab 仿真实现
  8. 2sin30°在python中如何表示_Python学习之基础练习(1)
  9. 深度神经网络的优点,深度神经网络的优势
  10. 工具教程第八讲:非小号行情软件使用