介绍一种在 ABAP 内核态进行内表高效拷贝的方法,和对应的 Java 和 JavaScript 版本的伪实现

内表操作是 ABAP 开发人员几乎在每个 ABAP 程序里都会遇到的。
看一个例子:有两个行结构不一样的内表,每个内表的行结构有三列,除了 name 这一列名字一致外,其他两列的名称都不同,下图用红色和蓝色标注出来。

如果要把内表 developer_list 里的两位开发人员 Jerry 和 Tom 的信息按照下图的映射关系拷贝到内表 presale_list 里:

常规做法当然是用一个 LOOP 循环,引入两个临时变量,先把内表 1 逐行赋给临时变量 1,再把临时变量 1 逐列赋给临时变量 2.

在 ABAP 750 版本里,提供了一个辅助类 cl_abap_corresponding,能以声明式编程的方式完成这个内表复制任务。
通过工具类的 create 方法,第二行和第三行指定要进行复制操作的源和目标内表,第四到六行告诉工具类内表复制的列字段映射规则。之后第 8 行调用 execute 方法完成复制操作。

大家更喜欢哪一种方式?这个例子虽然简单,但包含了一个编程领域的基础知识点:命令式编程(Imperative Programming)和声明式编程(Declarative Programming)。
第一种使用 LOOP 循环的解法是典型的命令式编程的例子,我们定义了两个临时变量,通过循环体内的三条赋值指令,命令代码去执行以完成内表拷贝。第二种解法, 作为应用开发人员,我们只是向工具类做出声明,我们想对哪两个内表根据什么样的映射逻辑进行拷贝。至于工作类如何执行,应用开发人员不操心,这就是声明式编程。
当然,即便是声明式编程,工具类的代码也总得有人实现。双击 execute 方法,发现是 ABAP 内核态的 C 语言实现的。
对于 SAP 客户和 partners 来说,无法看到这个 ab_kmMvcdExecute 内核方法的源代码,详情参考 Jerry 的文章:聊聊C语言和ABAP。

大家可以试着自己用 ABAP 来模拟实现一个自己的 CL_ABAP_CORRESPONDING. 这里 Jerry 提供一份 Java 版本的实现。
Java 里万物皆对象,所以我们分别定义 Developer 和 Presale 类:

创建两个 Java list 来模拟 ABAP 里的内表:

然后我的目的是,把第一个 list 里,Jerry 和 Tom 这两位开发者的 name, focusLanguage 和 salary 字段分别赋给第二个 list 对应实例的 name, focusArea 和 salaryPlusBonus 字段,模拟一个公司内部转岗的操作。
同 ABAP 使用工具类的方式一样,我声明了两条映射规则,分别是第二行的 mapping 实例 1,将 focusLanguage 字段直接赋给 focusArea 字段,以及第 5 行的 mapping 实例 2,将 salary 字段的值乘以 2,再赋给 salaryPlusBonus 字段。最后调用 execute 方法完成赋值。为了便于 ABAP 开发人员同之前的 ABAP 内表拷贝的例子进行比对,这里虽然是 Java 代码,但是 CL_MAPPING 和 CL_JAVA_CORRESPONDING 这两个类,我仍然用的是 ABAP 的命名规范,而非 Java 的驼峰式命名。

CL_JAVA_CORRESPONDING 的实现如下:execute 调用 map, map 调用 mapEach,提取用户指定的映射规则里的字段名,使用 Java 反射机制完成操作。

完整代码位于 Jerry 的github上:
再来看 Jerry 用 JavaScript 如何实现这个工具类的。先看在 JavaScript 里消费工具类的代码,仍然是声明式编程熟悉的味道:

因为 function 是 JavaScript 世界里的一等公民,所以 JavaScript 的实现版本,能写出更原汁原味函数式编程的解法出来:

如果要拷贝 JavaScript 版本的工具类 CL_JS_CORRESPONDING 的实现代码,可以从 Jerry 这篇博客里获得:
CL_ABAP_CORRESPONDING, CL_JAVA_CORRESPONDING and CL_JS_CORRESPONDING
希望这个简单的例子,能让大家感受到命令式编程和声明式编程的差异,感谢阅读。
版权声明: 本文为 InfoQ 作者【Jerry Wang】的原创文章。
原文链接:【http://xie.infoq.cn/article/c953b55a5f249c2cc5ed2d0ca】。文章转载请联系作者。
评论