最近研究了一下ABAP程序设计方面的东西,就提高程序可读性方面的问题进行了深入的分析与研究。结果发现相当一批人在设计方面走入一个误区,网上一些二把刀子的程序员发布的一些程序模版简直是误人子弟。在此,基于本人十余年的经验,提出以下几点建议。

一、规范化程序中的命名规则。有些在变量与内表命名的时候简直是随心所欲,毫无规律可言。同一类的表名多了,干脆直接XXX_1、XXX_2、XXX_3地排列下去。我们的ABAP程序虽然不能使用微软的匈牙利命名法,但是这种毫无意义的命名法更是不可取的。

二、多定义一些程序,使用子程序将程序功能模块化。SAP的ABAP编辑器是很不错的一个编辑器,它左边有导航条,通过双击可以轻易定位到每个子程序名与变量。使用子程序模块化程序后,定位程序功能非常的方便。

三、不要轻易使用INCLUDE程序。ABAP开发的程序培训教材中,曾经提到过模块化程序的两种方式,INCLUDE程序与子程序FORM。系统程序因为代码量大,大量使用了INCLUDE程序。有些人看到这里,就有样学样,在自己的开发程序中大量使用INCLUDE程序。其实这是完全没必要的。一般的自开发程序,如果代码规范良好的话,不会超过3000行,放在一个主程序里足够了。有些人把程序分成变量定义、选择屏幕与事件、PAI、PBO、子程序等四五个INCLUDE程序,自以为很给力。而实际上呢,子程序部分占所有代码的80%以上,而这个INCLUDE程序里定义的子程序却有聊聊无几,结果跟踪调试程序麻烦的要死。又因为与变量在不同的INCLUDE程序里,结果新增变量时比较麻烦,转而大量使用局部变量,使用程序的可读性更加糟糕。

四、灵活地使用宏。MACRO这个东西从C语言提出来以后,可以说常盛不衰。当然如果不愿意使用宏,用子程序来代替也是可以的。一个比较典型的例子就是给ALV的FIELDCAT内表添加输出字段。曾经见过一个输出50列的ALV报表,这部分的代码就写了400多行。查找字段时要翻好多屏才能找到。如果使用宏的话,这部分代码五六十行就够了。

五、控制嵌套缩进的空格数。大家会发现ABAP代码一行限制在72个字符之内,当然我们也可以取消这个限制。这其实提示我们,在嵌套缩进的时候,两个空格就够了,不要太多的缩进。以前有个同事喜欢缩进四个空格,结果子程序一层,LOOPAT循环一层,里面随便出现一个IF ESLE的判断。写到中间,代码都在每一行的中间开始,一行里根本写不多少东西。

六、控制嵌套的层数。有人可能会大声反对,我的程序就是需要这么多判断,我的程序就是需要双层循环。我很想问一句,真的是必须要这样做吗?我看到过一些人的代码,是的,IF判断就嵌套了三四层,再加上子程序一层、循环一层,搞得代码逻辑相当复杂。我只想提醒一句,有时候我们用一个CHECK判断一下就行,没必要一定嵌套进去。

七、合理地使用INNERJOIN。内连接,大家都是会的。国内某大型集团曾提出一个硬性要求,SQL语句的表连接不能超过3个,多么傻的一个要求呀。不合理的连接,两个连在一块就会要人命;而合理的连接有四五个表在一起也是没问题的。曾经遇到过一个极品ABAP顾问,一个1500行的程序,光数据处理的全局内表就定义了28个,程序中几乎没有一个连接取数的。当然,过多的连接也是不行的。当年培训一个JAVA出身的程序员,出了一个题目,就是要求取销售订单及后续交货单、发货过账的一些数据。这哥们没写,还振振有词地说太简单了,在系统中建立三个视图VBAK-VBAP-VBUK、LIKP-LIPS、MKPF-MSEG,然后视图内连接就出来了。哥当时真的是无话可说了,夏虫不可语冰,他还真以为SAP的ERP系统是他自己开发的ACCESS数据库呢!

八、注意一下小技巧的使用。ABAP程序的一些语句在处理一些特定的问题时特别有用,不要有意无意地忽略了这些语句。比如LOOPAT循环中的AT事件。有人在将一组数分类汇总并插到内表中时,又是内表,又是排序,搞得相当复杂。比如,财务的某一科目段,要按科目汇总一次,按科目的前6位汇总一次,按科目的前4位汇总一次,按科目的前2位汇总一次。这样的汇总,如果灵活使用ATENDOF事件,一个循环就能搞定。再比如,财务的月度报表,求期末汇总时,有人就会判断一个月份,然后再从上年结转到当月等一系列字段加起来。累不累呀?ADDHSLVT THEN HSL01 UNTILL HSLXX GIVING XXX,这语句多好用呀。

九、注意清空中间内表。有人不喜欢清空中间内表,认为程序结束后会自动清空。要是用户在结果屏幕上待上半天呢?何况有些处理大数量的程序如果不及时清空,本身跑起来就会耗费大量的内存资源。曾经一个报表,就一个CLEAR语句,就解决了其性能问题。

十、多了解点业务。有时候业务顾问给的数据逻辑能解决问题,但绝对不是最优的。我们完全可以采用更好的数据逻辑来处理数据。新项目上可能不用这样想,但一些优化项目上这么做是必须的。

一般情况下,我开发ABAP程序的时候,变量及类型的命名采用以下命名规则。可能不是最优的,但能回避相当多的问题。如果自己没制定出成形的命名规则,不妨使用一下,肯定比胡乱命名要好的多。

1、选择屏幕
 ·P_XXXX:PARAMETERS 定义的单值输入框
 ·S_XXXX:SELECT-OPTIONS 定义的范围输入框
 ·RADX:PARAMETERS 定义的 RADIOBUTION 类型的单选按钮
 ·CB_XXX:PARAMETERS 定义的 CHECKBOX 类型的复选框
 ·XXXX:选择屏幕上定义的输出块

2、程序内常用的变量与类型命名规则:使变量名称尽可能的表明变量的类型
 ·CON_XXX: 程序常量
 ·TYP_XX:程序内定义的结构类型
 ·TYP_T_XX:程序内定义的内表类型的结构类型

·R_XXXX:程序内定义的RANGES变量
 ·G_XXXX:程序内定义的全局变量
 ·GW_XXX:程序内定义的工作区:全局变量 也可以用 WA_XXX
 ·GT_XXX:程序内定义的内表:全局变量
 ·CL_XXX:全局类的变量声明
 · 全局的字段符声明,下划线前的两个字母根据字段符的类型确定
 ·MCR_XXXX:程序内定义的宏

·SUB_XXX:程序内定义的字程序
 ·LR_XXX: 子程序内定义的RANGE变量
 ·L_XXXX: 子程序内定义的局部变量
 ·LW_XXX:  子程序内定义的工作区:局部变量
 ·LT_XXX:  子程序内定义的内表:局部变量
 ·LC_XXXX:程序内定义的类 子程序内不建议定义类,如果定义使用此命名规则
 ·MCR_XXX 宏定义在一个程序中用的不是特别多,命名规则可以和全局宏的命名规则相同。

  以上命名的一个大规则就是,全局变量用一个母或是G加相应的类别字母开头;局部变量以L加相应的类别字母开头。子程序的形式参数的命名规则尊守局部变量的命名规则。

*  以下命名规则不是必须的
 ·STATUSX:程序内定义的状态
 ·PF_STATUS:程序内定义的用户状态

3、内表与变量的命名规则:使变量名称尽可能的表明变量的意义
 ·内表与工作区命名规则
  GT_EKKO:使用数据库表的表名,使内表名称表明主要保存的是哪个数据库表的数据
  GT_SUM_EKKO:在数据库表的表名前加一个简写单词,表明内表的主要用途,而不是用1\2\3等数字代替
  GT_RESULT:使用比较固定的单词,表明内表的主要使用目的,类似的常用内表名还有GT_EXCEL、GT_FIELD、GT_FIELDCAT
  GT_EVENTS:特定的地方,使用相对固定的内表名称(此名称是用在ALV的事件处理上的)
  GT_ITEMX: BAPI函数的内表则主要标明变量类别,意义则采用BAPI函数上的名称

 ·变量的命名规则:使变量名称尽可能的表明变量的意义
  G_DMBTR: 使用字段表明字段的类型与意义
  G_INDEX: 使用单词表明字段的意义,再如:G_ROW、G_COLWN、G_INDIC
  CL_GRID: 使用类别名或特定的字段来用到特定的对象上(此字段是ALV输出时常用的一个字段)
  G_MSG:  使用单词的简写来表明此字段的意义
  G_HSLXX: 当内容相近的字段比较多时,可以使用中文首母或数字来表明字段的内容(期间金额)

常用的ABAP程序模版,使用以下模版就不错。

*@---------------------------------------------------------------------*
*@ Report  ZTESTXUE68 常用的程序模版
*@ T-code
*@---------------------------------------------------------------------*
*@ Created by Xavery Hsueh(薛现军) on 2011-03-06
*@
*@ Lasted Edited date:
*@---------------------------------------------------------------------*
REPORT ztestxue68 NO STANDARD PAGE HEADING.

************************************************************************
**  声明数据库表 Declaration ofdatabase                             **
************************************************************************
TABLES:coep,
      coss.    "
************************************************************************
**  定义结构类型 Define the structure'stype                         **
************************************************************************

************************************************************************
**  定义变量与内表 Define the variants and Internaltables           **
************************************************************************

************************************************************************
**  宏定义 Define themacro                                          **
************************************************************************
DEFINE mcr_range.
  clear &1.
  &1-sign = 'I'.
  &1-option = &2.
  &1-low = &3.
  &1-high = &4.
  append &1.
END-OF-DEFINITION.
************************************************************************
**  选择屏幕 Customize theselection-screen                          **
************************************************************************
SELECTION-SCREEN BEGIN OF BLOCK xavery WITH FRAME TITLEtext_001.
PARAMETERS: p_erdat TYPE dats DEFAULTsy-datum.      "统计日期
PARAMETERS: p_kokrs TYPE kokrsOBLIGATORY.           "控制范围
SELECT-OPTIONS s_kstar FORcoep-kstar.               "成本要素
SELECTION-SCREEN END OF BLOCK xavery.
************************************************************************
**  执行程序事件 Executing the program'sevents                      **
************************************************************************
INITIALIZATION.
  PERFORM sub_init_cond.

START-OF-SELECTION.

PERFORM sub_query_vbak.

PERFORM sub_query_likp.

PERFORM sub_query_text.

PERFORM sub_prcess_data.

PERFORM sub_process_text.

END-OF-SELECTION.

输出结果内表的子程序调用

*@---------------------------------------------------------------------*
*@     Form  SUB_INIT_COND
*@---------------------------------------------------------------------*
*      初始化选择条件
*----------------------------------------------------------------------*
FORM sub_init_cond .
  text_001 = '选择屏幕'.
ENDFORM.                   " SUB_INIT_COND

  使用以上程序模版,将类型、变量、宏、子程序等放到相应的注释下,再加上SAP的导航栏,操作起来是非常方便的,这比使用INCLUDE程序要方便的多。

常用的ABAPALV程序模版。ABAP程序开发中,ALV报表的输出占了一半以上,基于这一点的考虑,ALV报表我一般使用如下的模版。

*&---------------------------------------------------------------------*
*& Report  ZTESTXUE56 采购订单发货跟踪表
*&
*&---------------------------------------------------------------------*
*& Created by Xavery Hsueh on 2014-02-13
*&
*&---------------------------------------------------------------------*
REPORT  ztestxue56 NO STANDARD PAGE HEADING.

************************************************************************
**  声明数据库表 Declaration ofdatabase                             **
************************************************************************
TABLES:ekko,
      ekpo,
      ekbe,
      lfa1.    "
************************************************************************
**  定义结构类型 Define the structure'stype                         **
************************************************************************
TYPES:BEGIN OF typ_result,
       ebeln TYPE ekpo-ebeln,
       ebelp TYPE ekpo-ebelp,
       lifnr TYPE ekko-lifnr,
       name1 TYPE lfa1-name1,
       matnr TYPE ekpo-matnr,
       maktx TYPE makt-maktx,
       matkl type mara-matkl,
       menge TYPEekpo-menge,    "采购订单数量
       bdmng TYPEekpo-menge,    "收货数量
       inmng TYPEekpo-menge,    "发票校验数量
       box   TYPE c,
     END OF typ_result.

TYPES:BEGIN OF typ_lfa1,
       lifnr TYPE lfa1-lifnr,
       name1 TYPE lfa1-name1,
     END OF typ_lfa1.

TYPES:BEGIN OF typ_ekbe,
       ebeln TYPE ekbe-ebeln,
       ebelp TYPE ekbe-ebelp,
       vgabe TYPE ekbe-vgabe,
       menge TYPE ekbe-menge,
       bwart TYPE ekbe-bwart,
     END OF typ_ekbe.
************************************************************************
**  定义变量与内表 Define the variants and Internaltables           **
************************************************************************
DATA:gt_result   TYPE TABLE OFtyp_result WITH HEADER LINE,
    gt_makt    TYPE TABLE OF makt WITH HEADER LINE,
    gt_lfa1    TYPE TABLE OF typ_lfa1 WITH HEADER LINE,
    gt_ekbe    TYPE TABLE OF typ_ekbe WITH HEADER LINE,
    gt_sum_ekbe TYPE TABLE OF typ_ekbe WITH HEADER LINE.

FIELD-SYMBOLS: TYPE typ_result.

TYPE-POOLS:slis.
DATA: cl_grid TYPE REF TO cl_gui_alv_grid,
     g_repid            LIKE sy-repid,
     g_structure_name   TYPE tabname,
     g_command          TYPE slis_formname,
     g_title            TYPE lvc_title,
     g_setting          TYPE lvc_s_glay,
     wa_print           TYPE slis_print_alv,
     gt_list_top_of_page TYPE slis_t_listheader,
     gt_events          TYPE slis_t_event WITH HEADER LINE,
     gt_sort            TYPE slis_t_sortinfo_alv,
     wa_sort            TYPE slis_sortinfo_alv,
     wa_layout          TYPE slis_layout_alv,
     gt_fieldcat        TYPE slis_t_fieldcat_alv,
     wa_fieldcat        LIKE LINE OF gt_fieldcat,
     g_field            TYPE char30,
     g_save             TYPE c,
     g_con_mark         TYPE slis_fieldcat_alv-fieldname VALUE 'MARK',
     g_length           TYPE i,
     g_pos              TYPE i.

FIELD-SYMBOLS:.
************************************************************************
**  宏定义 Define themacro                                          **
************************************************************************
DEFINE mcr_range.
  clear &1.
  &1-sign = 'I'.
  &1-option = &2.
  &1-low = &3.
  &1-high = &4.
  append &1.
END-OF-DEFINITION.
* 给FILEDCAT ALV内表赋值
DEFINE mcr_field.
  clear wa_fieldcat.
  clear g_field.
  g_pos = g_pos + 1 .
 wa_fieldcat-col_pos      =  g_pos.
  wa_fieldcat-fieldname = &1.
 wa_fieldcat-no_zero    = 'X'.
  wa_fieldcat-tabname = 'GT_RESULT'.
* wa_fieldcat-no_out ='X'.     "field no display, choose from layout
  wa_fieldcat-key =&2.        "SUBTOTAL KEY
  wa_fieldcat-seltext_l = &3.
* 计算输出字段的长度
  concatenate 'GT_RESULT-' &1 intog_field.
  assign (g_field) to .
  describe field output-length g_length.
  wa_fieldcat-outputlen = g_length.
  append wa_fieldcat to gt_fieldcat.
END-OF-DEFINITION.
************************************************************************
**  选择屏幕 Customize theselection-screen                          **
************************************************************************
SELECTION-SCREEN BEGIN OF BLOCK xavery WITH FRAME TITLEtext-001.
PARAMETERS:p_bsart TYPE ekko-bsart OBLIGATORY DEFAULT 'NB'.
SELECT-OPTIONS: s_lifnr FOR lfa1-lifnr,
               s_ekorg FOR ekko-ekorg,
               s_bedat FOR ekko-bedat.
SELECTION-SCREEN END OF BLOCK xavery.
************************************************************************
**  执行程序事件 Executing the program'sevents                      **
************************************************************************
INITIALIZATION.
  PERFORM sub_init_cond.

START-OF-SELECTION.
  PERFORM sub_query_ekbe.
  PERFORM sub_process_result.
  PERFORM sub_query_text.
  PERFORM sub_process_text.

END-OF-SELECTION.
  PERFORM sub_create_fieldcat.
  PERFORM sub_init_layout.
  PERFORM sub_display_as_alv. "以ALV的方式输出结果表
*@---------------------------------------------------------------------*
*@     Form  SUB_INIT_COND
*@---------------------------------------------------------------------*
*      初始化选择条件
*----------------------------------------------------------------------*
FORM sub_init_cond .

ENDFORM.                   " SUB_INIT_COND
*&---------------------------------------------------------------------*
*&     Form  SUB_QUERY_EKBE
*&---------------------------------------------------------------------*
*      查询采购订单相关的数据
*----------------------------------------------------------------------*
FORM sub_query_ekbe .
  SELECT ekko~ebeln
        ekpo~ebelp
        ekpo~matnr
        ekpo~menge
        ekpo~matkl
        ekpo~elikz
        ekko~lifnr
     FROM ekko INNER JOIN ekpo ON ekko~ebeln = ekpo~ebeln
     INTO CORRESPONDING FIELDS OF TABLE gt_result
     WHERE bsart EQ p_bsart AND
           ekorg IN s_ekorg AND
           lifnr IN s_lifnr AND
           bedat IN s_bedat.

CHECK gt_result[] IS NOT INITIAL.
  SELECT ebeln
        ebelp
        vgabe
        menge
        bwart
     FROM ekbe
     INTO TABLE gt_ekbe
     FOR ALL ENTRIES IN gt_result
     WHERE ebeln = gt_result-ebeln AND
           ebelp = gt_result-ebelp.

SORT gt_ekbe BY ebeln ebelp vgabe.
  LOOP AT gt_ekbe.
    AT NEWvgabe.
     CLEAR gt_sum_ekbe.
    ENDAT.
   gt_sum_ekbe-ebeln = gt_ekbe-ebeln.
   gt_sum_ekbe-ebelp = gt_ekbe-ebelp.
   gt_sum_ekbe-vgabe = gt_ekbe-vgabe.

IFgt_ekbe-bwart = '101' OR gt_ekbe-bwart = ''.
     gt_sum_ekbe-menge = gt_sum_ekbe-menge + gt_ekbe-menge.
    ELSEIFgt_ekbe-bwart = '102'.
     gt_sum_ekbe-menge = gt_sum_ekbe-menge - gt_ekbe-menge.
    ENDIF.

AT END OFvgabe.
     APPEND gt_sum_ekbe.
    ENDAT.
  ENDLOOP.
* 释放中间内表
  FREE:gt_ekbe.
ENDFORM.                   " SUB_QUERY_EKBE
*&---------------------------------------------------------------------*
*&     Form  SUB_QUERY_TEXT
*&---------------------------------------------------------------------*
*      查询文本描述信息
*----------------------------------------------------------------------*
FORM sub_query_text .
  CHECK gt_result[] IS NOT INITIAL.
  SELECT * FROM makt
     INTO TABLE gt_makt
     FOR ALL ENTRIES IN gt_result
     WHERE matnr = gt_result-matnr AND
           spras = sy-langu.

SELECT lifnr
        name1
     FROM lfa1
     INTO TABLE gt_lfa1
     FOR ALL ENTRIES IN gt_result
     WHERE lifnr = gt_result-lifnr.
ENDFORM.                   " SUB_QUERY_TEXT
*&---------------------------------------------------------------------*
*&     Form  SUB_PROCESS_RESULT
*&---------------------------------------------------------------------*
*      将采购订单数据更新到结果内表
*----------------------------------------------------------------------*
FORM sub_process_result .
  SORT gt_sum_ekbe BY ebeln ebelp vgabe.
  LOOP AT gt_result ASSIGNING .
    CLEARgt_sum_ekbe.
    READ TABLEgt_sum_ekbe WITH KEY ebeln = -ebeln
                                   ebelp = -ebelp
                                   vgabe = 1
                                   BINARY SEARCH.
    IF sy-subrc= 0.
     -bdmng = gt_sum_ekbe-menge.
    ENDIF.

CLEARgt_sum_ekbe.
    READ TABLEgt_sum_ekbe WITH KEY ebeln = -ebeln
                                   ebelp = -ebelp
                                   vgabe = 2
                                   BINARY SEARCH.
    IF sy-subrc= 0.
     -inmng = gt_sum_ekbe-menge.
    ENDIF.
  ENDLOOP.
* 释放中间内表
  FREE:gt_sum_ekbe.
ENDFORM.                   " SUB_PROCESS_RESULT
*&---------------------------------------------------------------------*
*&     Form  SUB_PROCESS_TEXT
*&---------------------------------------------------------------------*
*      将文本信息更新到结果内表
*----------------------------------------------------------------------*
FORM sub_process_text .
  SORT gt_makt BY matnr.
  SORT gt_lfa1 BY lifnr.
  LOOP AT gt_result ASSIGNING .
    CLEARgt_makt.
    READ TABLEgt_makt WITH KEY matnr = -matnr
                               BINARY SEARCH.
    IF sy-subrc= 0.
     -maktx = gt_makt-maktx.
    ENDIF.

CLEARgt_lfa1.
    READ TABLEgt_lfa1 WITH KEY lifnr = -lifnr
                               BINARY SEARCH.
    IF sy-subrc= 0.
     -name1 = gt_lfa1-name1.
    ENDIF.
  ENDLOOP.
* 释放中间内表
  FREE:gt_makt,
      gt_lfa1.
ENDFORM.                   " SUB_PROCESS_TEXT
*&---------------------------------------------------------------------*
*&     Form  SUB_CREATE_FIELDCAT
*&---------------------------------------------------------------------*
*      给输出的结果内表指定字段
*----------------------------------------------------------------------*
FORM sub_create_fieldcat .
  CLEAR gt_fieldcat[].
  mcr_field 'EBELN'   'X'    '采购订单号'.
  mcr_field 'EBELP'   'X'    '订单行项目'.
  mcr_field 'LIFNR'   ''    '供应商账号' .
  mcr_field 'NAME1'   ''    '供应商名称' .
  mcr_field 'MATNR'   ''    '物料编号' .
  mcr_field 'MATKL'   ''    '物料组'.
  mcr_field 'MAKTX'   ''    '物料描述'.
  mcr_field 'MENGE'   ''    '订单数量' .
  mcr_field 'BDMNG'   ''    '收货数量' .
  mcr_field 'INMNG'   ''    '发票校验数量' .
ENDFORM.                   " SUB_CREATE_FIELDCAT
*&---------------------------------------------------------------------*
*&     Form  SUB_INIT_LAYOUT
*&---------------------------------------------------------------------*
*      设置常用的输出布局参数
*----------------------------------------------------------------------*
FORM sub_init_layout .
 wa_layout-zebra            = 'X'.
 wa_layout-window_titlebar   ='采购发货跟踪表'.
  wa_layout-colwidth_optimize = 'X'.
 wa_layout-box_fieldname    = 'BOX'.
 wa_layout-header_text      = '选择'.
ENDFORM.                   " SUB_INIT_LAYOUT
*&---------------------------------------------------------------------*
*&     Form  SUB_DISPLAY_AS_ALV
*&---------------------------------------------------------------------*
*      调用 ALV 的FUNCTION来输出结果
*----------------------------------------------------------------------*
FORM sub_display_as_alv .
  g_repid = sy-repid.
  g_setting-coll_top_p ='X'.      "最小化 CALLBACK-TOP-OF-PAGE.
* ABAP List Viewer
  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
   EXPORTING
     i_callback_program      = g_repid
     i_structure_name        = 'TYP_RESULT'
     i_grid_title            = g_title
     i_grid_settings         = g_setting
     i_callback_user_command  ='SUB_USER_COMMAND'
     i_callback_pf_status_set = 'SUB_SET_PF_STATUS'
     i_save                  = g_save
     is_layout               = wa_layout
     it_fieldcat             = gt_fieldcat[]
    TABLES
     t_outtab                = gt_result
   EXCEPTIONS
     program_error           = 1
     OTHERS                  = 2.
ENDFORM.                   " SUB_DISPLAY_AS_ALV
*@---------------------------------------------------------------------*
*@      FORMSUB_SET_PF_STATUS                                       *
*@---------------------------------------------------------------------*
*  设置ALV菜单
* 通过SE41,拷贝程序SAPLSLVC_FULLSCREEN的状态STANDARD_FULLSCREEN过来
*@---------------------------------------------------------------------*
FORM sub_set_pf_status USING rt_extab TYPE slis_t_extab.
  SET PF-STATUS 'STANDARD_FULLSCREEN'.
ENDFORM.                   "sub_set_pf_status
*@--------------------------------------------------------------------*
*@     Form  sub_user_command
*@--------------------------------------------------------------------*
*     -->R_UCOMM    事务功能码
*     -->RS_SELFIELD ALV相关的数据
*---------------------------------------------------------------------*
FORM sub_user_command USINGr_ucomm   LIKE sy-ucomm
                       rs_selfield TYPE slis_selfield.
  DATA l_ebeln TYPE ekko-ebeln.
  l_ebeln = rs_selfield-value+0(10).
  CASE r_ucomm.
    WHEN'&IC1'.                "双击事件的功能码
     PERFORM sub_ucomm_double_click USING l_ebeln.
    WHEN'EDIT'.             "刷新订单的特性值
*     PERFORM sub_ucomm_update.
    WHENOTHERS.
  ENDCASE.
* 刷新ALV报表
  rs_selfield-refresh = 'X'.

ENDFORM.                   "sub_user_command
*&---------------------------------------------------------------------*
*&     Form  SUB_UCOMM_DOUBLE_CLICK
*&---------------------------------------------------------------------*
*      实现ALV 的双击跳转功能
*----------------------------------------------------------------------*
FORM sub_ucomm_double_click USING l_ebeln TYPE ekko-ebeln.
  CALL FUNCTION'ME_DISPLAY_PURCHASE_DOCUMENT'
   EXPORTING
     i_ebeln             = l_ebeln
   EXCEPTIONS
     not_found           = 1
     no_authority        = 2
     invalid_call        = 3
     preview_not_possible = 4
     OTHERS              = 5.
  IF sy-subrc <> 0.
    MESSAGE IDsy-msgid TYPE sy-msgty NUMBER sy-msgno
           WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.
ENDFORM.                   " SUB_UCOMM_DOUBLE_CLICK

  本程序是一个项目上的实用程序,几经修订后变成了我常用的ALV程序的模版。

1、首先,ALV的变量是比较全的。一般情况下的ALV报表输出,不用再新增输出格式相关的变量。再是ALV报表的几个子程序也是固定的,使用ALV 输出,只要将这些子程序COPY过去,再做简单的修改就可以满足了。

2、本程序的命名规则也是很规范的。本程序曾经扩展到2000多行,业务延伸到了应付账款及账龄分析。在命名统一、子程序模块化的情况下,一点都不杂乱。移交给客户时非常的简单明了。不会因为逻辑的混乱而产生什么误解。

3、注意子程序的模块化。虽然只是五六百行的小程序,但取数与处理部分仍然分成了四个子程序。这在阅读程序的时候,只要双击一下START-OF-SELECTION,就可以找到相应的目录,非常简单位。扩展的时候也是先在事件下添加子程序调用,再双击子程序创建的。若一个子程序的代码超过三四百行,此程序的可读性就大大降低了。

4、程序的缩进与SQL的查询都很规范。缩进就不说了,一目了然。SQL的查询中,本程序使用了一定的内连接,简化了代码。在循环处理进又采用了BINARYSEARCH等小技巧,程序性能相当地出众。每个子程序的结束都将过期的内表释放掉,节约了内存。

ABAP程序设计的一点建议相关推荐

  1. 【职场】肺腑之言,给即将参加秋招的同学一点建议

    文章来源于AI的那些事儿,作者黄鸿波 7月份到了,很多公司都陆陆续续的开启了秋招的进程,也有不少2021年毕业的同学也都在积极的准备着,并且也有很多同学都已经进入到了提前批的面试阶段.今天我就结合我自 ...

  2. 阳光学院计算机科学与技术需要英语四级,给各位想报阳光的朋友一点建议!来自学长的亲身经历!...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 给各位想报阳光的朋友一点建议!来自学长的亲身经历! 首先,不要期望阳光学院的师资有多好.从师资上来说,阳光学院早期聘用的是福大的老师没错,但是阳光现在为了 ...

  3. Mysql数据库的瓶颈处理一点建议

    Mysql数据库的瓶颈处理一点建议         我们在使用Mysql数据库是常见的两个瓶颈是CPU和I/O的瓶颈,CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候.磁盘I/O瓶颈的出 ...

  4. #今日论文推荐# 陈天奇、王威廉等人推荐:ACL最佳论文奖得主给新入行研究者的一点建议

    #今日论文推荐# 陈天奇.王威廉等人推荐:ACL最佳论文奖得主给新入行研究者的一点建议 本文将对两篇篇博客的中心思想进行了编译整理(以第一人称转述),内容如下: 前提:扩展你的相邻可能 想法往往出现在 ...

  5. 学校计算机基础做慢了扣分,中职学校《计算机应用基础》课程改革的一点建议...

    中职学校<计算机应用基础>课程改革的一点建议 论文关键词:课程改革 任务驱动 模式化教学 过程性评价 教育技术 论文摘要:本文针对目前中职学校中学生的现状,以及计算机应用基拙教学中存在的问 ...

  6. 中职学校计算机应用基础学什么,浅谈中职学校《计算机应用基础》课程改革的一点建议...

    <浅谈中职学校<计算机应用基础>课程改革的一点建议>由会员分享,可在线阅读,更多相关<浅谈中职学校<计算机应用基础>课程改革的一点建议(3页珍藏版)>请 ...

  7. 给B2C网站企业的一点建议

    在周末时,我有了一次不太愉快的购物体验,自己经常使用的一款洗面奶用完了,但在周边超市购物时,并没有发现有该牌子的洗面奶销售,考虑到可以等待几天,故考虑从唯品会或者乐蜂上购买购买(个人看法:淘宝信不过, ...

  8. 给在北漂准备租房的菜鸟一点建议

    最近这两天很烦,因为租房子的事情.事情现在还没算处理完,但是这次也被教育了,给在北漂准备租房的菜鸟一点建议(不喜勿喷) 我之前一直在上家公司的宿舍住,地点北京丰台郊区,那边没有地铁但是距离工作地点近. ...

  9. 上交大计算机复试机师难不难,一个去年考交大复试被刷的人给大家一点建议(更新)...

    呵呵,很少来上网,不过看到现在的数学版真的是比去年差多了,有些话心里想说很久了,一直没机会说,因为很少有机会说,不过我蛮担心有些人学习方法不恰当,所以来谈谈过来人的建议. 我去年考交大信息安全学院通信 ...

最新文章

  1. Node中使用mysql模块遇到的问题
  2. 并发环境下,先操作数据库还是先操作缓存?
  3. Effective Java之覆盖equal时要遵守通用约定(八)
  4. 回归树与基于规则的模型(part2)--简单回归树
  5. 张腾:腾讯云融合通信应用场景及案例分享
  6. oracle dump enq hw,经典故障分析 - ASSM引发的索引争用与 enq HW -contentio
  7. 密码学在区块链中的应用 【八】
  8. TKDragView_TKCalendarView:页面curl的动画日历
  9. 64如何传入后台_如何保证API接口数据安全?
  10. android gridvie item,Android开发―解决自定义GridView高度第一个item高度异常问题
  11. xrld读取excel 中合并单元格内容
  12. 使用echars制作家谱图
  13. Android ViewBinding使用详解
  14. 查杀计算机病毒,计算机病毒查杀
  15. MySQL Server 5.7.13
  16. Perl中use strict
  17. HTML+CSS入到到精通
  18. JiangxiBank
  19. 如何理解 “Dense object detection“中的dense?
  20. Linux系统简介及简要shell命令介绍(2)

热门文章

  1. 乐峰VS聚美,明星也要吃咸盐
  2. javax.mail 发送
  3. 获取标签的src属性兼容性
  4. c# 如何设置透明画刷
  5. aix source 命令
  6. 集合objectjava_collection
  7. jsp基础语法【05】_跳转指令
  8. Hadoop 统计单词字数的例子
  9. 【洛谷 P2763】 试题库问题(最大流)
  10. [译] 你是如何拆分组件的?