一种用于ABAP Report重构的面向对象设计方法——MVC

1 篇文章 0 订阅
1 篇文章 0 订阅


原文地址:http://zevolving.com/2013/03/abap-object-oriented-approach-for-reports-redesign/

By Naimesh Patel | March 27, 2013 | ABAP Objects, OO Design Patterns


在本篇文章中,我将使用ABAP对象向你展示一种更加灵活的设计。该设计用于尽可能的解耦业务逻辑、参数、数据展示。


介绍

如前一篇文章讨论所述(一种用于ABAP面向对象的Report的初始设计,其得到了非常好的反响),我看到很多开发者在试图使用面向对象时遵循了糟糕的设计。由于那样的设计没有利用任何面向对象的特性,我通常将他们成为伪对象设计。


我将向你展示如何用面向对象的设计实现我在前一篇文章中提到的例子。这个方法纯粹基于MVC的设计模式。如果你对MVC还不是很熟悉,我建议你可以阅读我更早的3篇系列文章——可以从《ABAP Objects Design Patterns – Model View Controller (MVC) Part 1》这篇开始。


相关对象

为制作这个简单的报表程序,我将创建三个类:

  • SEL-选择参数类
  • DATA(Model)-数据选择和处理类(类似于模型类)
  • ALV(View)-用于展示数据的类
这里所有的想法都是为了尽可能的解耦。所以,基于此,我将把所有与业务逻辑相关的数据选择和处理都放在DATA类中。这个DATA类将有不同的方法去检索和处理基于选择参数的数据。为了避免把选择条件作为参数嵌入在DATA类中,我将它们放在一个单独的类中-SEL类。这将给我一个优势,可以将SEL对象传递给DATA类和ALV类(如果需要那样做的话)。下一步是解耦报表程序的显示相关功能。所以我会创建一个ALV类。

UML设计

uml基本设计如下:

另外我已经创建了一个Exception类ZCX_MSG,用于处理来自于对象模型的例外情况。如果你还不熟悉基于Exception的类,我建议你读一下我的另一个系列文章,可以从《Class-based Exceptions I – Basics》开始学习如何使用它。


SEL类

SEL类负责在需要的时候将属性传递给模型和视图。因为选择参数没有被嵌入在模型类中,你可以简单的将对象传递给另一个模型类。SEL类的职责和属性:
  • 包含所有来自于选择屏幕的参数和选项
  • 包含选择屏幕上的自动生成的默认值的方法
  • 包含验证选择屏幕数据合法性的方法
  • 所有属性将仅在处理START-OF-SELECTION事件时被设置
Demo:SEL类的代码行——ZCL_REPORT_T100_SEL

这个SEL类的例子包含两个属性用于保存选择条件。它还有两个方法,GET_DEFAULT方法用于设置默认值,VALIDATE_MESSAGE_CLASS用于参数合法性验证。


ZCL_REPORT_T100_SEL代码行:

* Types for the Attributes
  TYPES:
    tt_MSGNR_Range TYPE RANGE OF t100-MSGNR .
 
  DATA V_ARBGB TYPE T100-ARBGB .
  DATA T_MSGNR_RANGE TYPE TT_MSGNR_RANGE .
*
CLASS ZCL_REPORT_T100_SEL IMPLEMENTATION.
  METHOD GET_DEFAULT.
"     returning value(RV_ARBGB) type T100-ARBGB .
    rv_arbgb = '00'.
  ENDMETHOD.
*
  METHOD validate_message_class.
"    importing !IV_ARBGB type T100-ARBGB
"    raising   ZCX_MSG .
    DATA: ls_msg TYPE symsg.
    SELECT SINGLE arbgb
      INTO v_arbgb
      FROM t100
      WHERE arbgb = iv_arbgb.
    IF sy-subrc NE 0.
      ls_msg-msgty ='E'.
      ls_msg-msgid ='00'.
      ls_msg-msgno = '398'.
      ls_msg-msgv1 = 'No Message class found'.
      RAISE EXCEPTION TYPE zcx_msg
        EXPORTING
          msg = ls_msg.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

DATA类

DATA类负责抓取数据并以期望的格式输出。典型的数据类职责如下:
  • 包含用于数据选择的所有方法
  • 将使用来自于SEL对象的属性用于数据选择和筛选
  • 将包含实例属性。仅仅只有一个需要被暴露给外界的属性被声明为Public,剩下的全部声明为Private。
  • 这可以反过来根据需要使用不同的对象
Demo:DATA类——ZCL_REPORT_T100_DATA

这个类包含两个属性:O_SEL——类型为ZCL_REPORT_T100_SEL,T_T100——类型为TABLE T100,用于存放筛选后的数据。在构造方法中,我们为O_SEL做初始化赋值。GET_DATA方法使用SEL对象的属性筛选数据。


DATA类ZCL_REPORT_T100_DATA的代码行:

CLASS ZCL_REPORT_T100_DATA IMPLEMENTATION.
  METHOD CONSTRUCTOR.
"    importing !IO_SEL type ref to ZCL_REPORT_T100_SEL .
    me->o_Sel = io_sel.
  ENDMETHOD.
*
  METHOD GET_DATA.
    SELECT * FROM t100
      INTO TABLE t_t100
      WHERE arbgb =  me->o_sel->v_arbgb
      AND   msgnr IN me->o_Sel->T_MSGNR_RANGE.
  ENDMETHOD.
ENDCLASS.

ALV类

典型的View类负责向调用者显示数据以及任何处理操作。ALV类:

  • 将包含有关ALV处理的逻辑
  • 也包含用于处理任何需要事件的事件处理方法
  • 将包含一个DATA类的属性。这是一个Public属性,因此外部将可以获取DATA的内容。
Demo:ALV类——ZCL_REPORT_T100_ALV

这个类包含两个属性:ZCL_REPORT_T100_DATA类型的O_DATA和CL_SALV_TABLE类型的O_SALV。包含一些方法:构造方法用于设置DATA对象,GENERATE_ALV用于声场简单的ALV报表。


ALV类ZCL_REPORT_T100_ALV的代码行:

CLASS ZCL_REPORT_T100_ALV IMPLEMENTATION.
  METHOD CONSTRUCTOR.
"   importing !IO_DATA type ref to ZCL_REPORT_T100_DATA .
    me->o_Data = io_data.
  ENDMETHOD.
*
  METHOD GENERATE_ALV.
    TRY.
        CALL METHOD cl_salv_table=>factory
          IMPORTING
            r_salv_table = me->o_salv
          CHANGING
            t_table      = me->o_data->t_t100.
*  
        me->o_salv->display( ).
*  
      CATCH cx_salv_msg .
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

基于面向对象设计方法的程序

这是根据以上声明的类重新设计的程序代码版本。
*&---------------------------------------------------------------------*
*& Purpose - Object Oriented Implementation for a Report
*& Author  - Naimesh Patel
*& URL     - http://zevolving.com/?p=2045
*&---------------------------------------------------------------------*
REPORT ztest_np_t100_OO_report.
*
DATA: v_msgnr TYPE t100-msgnr.   " for selection screen
*
DATA: o_data TYPE REF TO zcl_report_t100_data.
DATA: o_sel  TYPE REF TO zcl_report_t100_sel.
DATA: o_alv  TYPE REF TO zcl_report_t100_alv.
DATA: o_exc  TYPE REF TO zcx_msg.
*
SELECTION-SCREEN: BEGIN OF BLOCK blk1 WITH FRAME TITLE text-t01.
PARAMETERS:     p_arbgb TYPE t100-arbgb OBLIGATORY.
SELECT-OPTIONS: s_msgno FOR v_msgnr.
SELECTION-SCREEN: END OF BLOCK blk1.
*
INITIALIZATION.
  CREATE OBJECT o_sel.
  CREATE OBJECT o_data EXPORTING io_sel  = o_sel.
  CREATE OBJECT o_alv  EXPORTING io_data = o_data.
  p_arbgb = o_sel->get_default( ).
*
AT SELECTION-SCREEN ON p_arbgb.
  TRY.
      o_sel->validate_message_class( p_arbgb ).
    CATCH zcx_msg INTO o_exc.
      MESSAGE ID o_exc->msg-msgid TYPE o_exc->msg-msgty
              NUMBER o_exc->msg-msgno
              WITH  o_exc->msg-msgv1 o_exc->msg-msgv2
                    o_exc->msg-msgv3 o_exc->msg-msgv4.
  ENDTRY.
*
START-OF-SELECTION.
" Set the attributes of the SEL object from the
" Selection screen parameters & Options
  o_sel->v_arbgb = p_arbgb.
  o_sel->t_msgnr_range = s_msgno[].
*
* Get the data
  o_data->get_data( ).
*
* Generate the ALV
  o_alv->generate_alv( ).

demo程序的UML

这是从UML角度看以上程序的样子。



优点

这种面向对象的设计确实比面向过程的方法需要更多的努力来实现,但是这将获得更多的灵活性以及更少的维护——降低总体拥有成本(TCO)。
  • 由于模型类从主程序中解耦出来,它独立运作。这样使得它能更加方便的扩展并可用于不同的视图中。
  • 分离的SEL对象使得不用在方法中与使用选择屏幕参数和选项耦合。这比使用任何选择屏幕更加独立。只要你设置合适的属性,你将能够用DATA类来使用它。
  • 分离视图提高了可重用性
考虑一下用同样的逻辑开发一个WebDynpro——设置合适的参数给SEL对象,实例化DATA类并调用方法获得数据。将数据传递给视图WebDynpro去生成输出。
或者,想一想,有一个已存在的复杂设计需要展示这些数据,可以以上述同样的方法直接获取你所期望的数据输出。

你怎么认为?

你会愿意使用这样的设计吗?你认为它是一个好方法吗?或者是一个过度设计?


  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值