SAP/ABAP 기초

(ABAP) FORM 과 MODULARIZATION

haramang 2021. 6. 20. 22:11

- MODULARIZATION

  •  Modularization unit은 프로그램의 일부분으로써, 특정 부분의 Source Code나 Logic을 은닉화한다. 예로 들면, 일정 부분의 코드들을 모듈화 시켜 (Form) 전체적인 프로그램의 흐름을 이해하기 쉽게 하거나, Function이나 Method를 사용하여 자주 사용되는 코드들을 다시 작성할 필요 없이, 필요할 때마다 꺼내 쓸 수 있다.
  • Modularization을 함으로써 프로그램 관리가 용이해진다. 예로 들면, 어떤 특정한 코드를 추가하거나 프로그램 내에서 수정을 해야 할 때, 프로그램 전체를 마우스로 스크롤하면서 찾기보다는, 관련된 해당 모듈이나 Function 혹은 Method를 수정하는 게 편하기 때문이다. 또한, 코드 에러를 찾을 때도 편할 것 같다.
  • Local Program Modularization으로는 FORM문과 Local Class를 사용하며, 오직 프로그램내에서만 접근이 가능하다. 다른 프로그램에서는 사용할 수 없다는 소리. (사실 사용할 수 있으나, 그러지 말라고 한다.)
  • Global Modularization으로는 Function이나 Method를 사용한다. Form문과는 달리, 모든 프로그램에서 Function과 Method를 사용할 수 있다.
  • Encapsulation(은닉화)에 대하여...
    • 모듈화 된 유닛은 메인 프로그램의 Data Object를 직접적으로 사용할 수 없으며, 메인 프로그램은 모듈화 된 유닛에 있는 데이터들을 변경할 수 없다.
    • 무슨 소리인가 하면, 아래 예제에서 보겠지만 메인 프로그램에서 FORM 서브루틴으로 보내는 변수들의 이름과 FORM 서브루틴 내의 변수들의 이름이 다르다. 해당 변수들의 Data Type은 동일하지만 다른 변수 이름으로 관리하겠다는 거다. 이로 인해, 메인 프로그램과 서브루틴은 서로 Data Object를 직접 사용하지 않고 값도 직접적으로 바꿀 수 없다. 

 

 

- Pass Types for Subroutines

  Call by Reference와 Call by value and result, 그리고 Call by reference가 존재한다.

  • Call by value
    • 메인 프로그램의 변수를 서브루틴에서 변경하고 별 짓을 다해도 메인 프로그램으로 돌아왔을 땐 기존값이 유지된다.
  • Call by value and result
    • 기본적으로 Call by value와 성격이 같으나, 다시 메인 프로그램으로 돌아갔을 때, 기존 변수의 값이 서브루틴에서 변경된 값으로 바뀐다. 중요한 점은, 무조건 바뀌는게 아니라 FORM 서브루틴에서 모든 Logic이 정상적으로 완료되었을 때만 바뀐다. 예로 들면, FORM 서브루틴에서 STOP을 만나거나 에러가 발생해서 모든 서브루틴 Logic을 완료하지 못했을 경우 Call by value와 같이 메인 프로그램의 변수 값은 변경되지 않은 채로 기존 값을 갖는다.
  • Call by Reference
    • FORM 서브루틴내에서 메인 프로그램의 변숫값이 변경되면 메인 프로그램의 변수 값도 같이 변경된다. 서브루틴에서 메인 프로그램의 변숫값을 변경하고 다시 돌아왔을 때, 그 변수가 기존 값을 유지하는 Call by Value와는 다른 개념이다.
" TEST_SUBROUTINE 서브루틴으로 가는 PERFORM 문
PERFORM TEST_SUBROUTINE
      USING NUM1
      CHANGING NUM2
                      NUM3.


" TEST_SUBROUTINE 서브루틴
FORM TEST_SUBROUTINE
       USING VALUE(NUM1)
       CHANGING VALUE(NUM2)
                       NUM3.

USING의 변수를 VALUE()로 감싸면, Call By Value로 선언.
CHANGING의 변수를 VALUE()로 감싸면, Call By Value and Result로 선언.
CHANGING의 변수를 VALUE() 없이 사용하면 Call By Reference로 선언.

 

 

- FORM 사용하기

예제1) Parameter를 FORM 구문에 보내지 않는 FORM구문

FORM 서브루틴에 아무런 Parameter를 보내지 않고 사용한다. 이렇게 사용할 경우 NUM1과 NUM2 그리고 NUM3의 변수들은 동일 이름으로 FORM 서브루틴 내에서 사용된다.

DATA: NUM1   TYPE I,
      NUM2   TYPE I,
      RESULT TYPE I.

NUM1 = 1.
NUM2 = 2.

 
" ADDITION FORM 서브루틴으로 간다.
PERFORM ADDITION.

" 결과 값 확인
WRITE:/ 'NUM1 + NUM2 = ', RESULT.


" FORM 서브루틴
FORM ADDITION.

  RESULT = NUM1 + NUM2.

ENDFORM.

결과값.

 

예제 2) Parameter를 FORM 구문에 보내는 FORM구문

FORM 서브루틴에 아무런 Parameter를 보내서 사용한다. 이렇게 사용할 경우 NUM1과 NUM2 그리고 NUM3의 변수들은 FORM 서브루틴 내에서 다른 이름으로 사용되지만 Data Type은 같다.

USING 이후에 넣는 변수들을 PARAMETER라고 하며, CHANGING의 변수는 FORM 구문 이후에 결괏값이 저장될 것이다.


DATA: NUM1   TYPE I,
      NUM2   TYPE I,
      RESULT TYPE I.

NUM1 = 1.
NUM2 = 2.


" NUM1과 NUM2를 FORM 서브루틴으로 보내고,
" 결과를 RESULT로 받는다.

PERFORM ADDITION_PARAMETER
    USING       NUM1
                    NUM2
    CHANGING RESULT.

WRITE:/ 'NUM1 + NUM2 = ', RESULT.

 
" FORM 서브루틴에는 P_가 추가로 붙는다.
FORM ADDITION_PARAMETER  USING    P_NUM1 TYPE I     " 메인 프로그램의 NUM1과 같음
                                                      P_NUM2 TYPE I     " 메인프로그램의 NUM2와 같음
                                                      CHANGING P_RESULT TYPE I.  " 메인프로그램의 NUM3과 같음

  " P_NUM1에는 NUM1에 저장된 값 1이,
  " P_NUM2에는 NUM2에 저장된 값 2가,
  " P_RESULT에는 P_NUM1과 P_NUM2의 값인 1과 2를 더한 값 3이 저장된다.

  P_RESULT = P_NUM1 + P_NUM2.

  "ENDFORM 이후 P_RESULT는 메인프로그램의 RESULT변수에(CHANGING에 세팅된) 저장된다.

ENDFORM.

결과값.

 

예제 3) INTERNAL TABLE을 Parameter로 보내는 FORM 구문


* Data Object 선언
TABLES : SCARR.
SELECT-OPTIONS: SO_CARR FOR SCARR-CARRID DEFAULT 'AA'.
DATA: GS_ITAB TYPE SFLIGHT,
      GT_ITAB LIKE TABLE OF GS_ITAB,
      LV_NUM1 TYPE I,
      LV_NUM2 TYPE I.


* SELECT-OPTIONS 변수인 SO_CARR의 범위에 설정된 AIRLINE CODE가 
* SFLIGHT에 있는 CARRID와 동일한 데이터 들만 ITAB에 저장

SELECT *
  FROM SFLIGHT
  INTO TABLE @DATA(ITAB)
  WHERE CARRID IN @SO_CARR.

 
* ITAB에 있는 데이터를 GT_ITAB으로 복사.
MOVE-CORRESPONDING ITAB TO GT_ITAB.

* LV_NUM1을 1로 지정
LV_NUM1 = 1.


* MOVE_INTERNAL_TABLE 서브루틴으로 이동
* LV_NU1의 값을 LV_NUM2에 넣고, GT_ITAB(Internal Table)도 Parameter로 보낸다.
* Table은 CHANGING으로 받지 않는다 ( Pass by Reference로 서브루틴 내에서 값이 바뀌면
* 메인 프로그램 내에서도 똑같이 바뀜.
PERFORM MOVE_INTERNAL_TABLE TABLES GT_ITAB
                                USING LV_NUM1
                          CHANGING LV_NUM2.


LOOP AT GT_ITAB INTO GS_ITAB.
  WRITE:/
    GS_ITAB-CARRID            ,
    GS_ITAB-CONNID            ,
    GS_ITAB-FLDATE            ,
    GS_ITAB-PRICE             ,
    GS_ITAB-CURRENCY          ,
    GS_ITAB-PLANETYPE         ,
    GS_ITAB-SEATSMAX          ,
    GS_ITAB-SEATSOCC          ,
    GS_ITAB-PAYMENTSUM        ,
    GS_ITAB-SEATSMAX_B        ,
    GS_ITAB-SEATSOCC_B        ,
    GS_ITAB-SEATSMAX_F        ,
    GS_ITAB-SEATSOCC_F        .
ENDLOOP.



 
* FORM 서브루틴
FORM MOVE_INTERNAL_TABLE  TABLES   P_GT_ITAB STRUCTURE GS_ITAB
                             USING    P_LV_NUM1 TYPE I
                          CHANGING P_LV_NUM2 TYPE I.

 
  " P_LV_NUM2에 P_LV_NUM1의 값을 저장. P_LV_NUM1에는 1이 저장되어 있음.
  P_LV_NUM2 = P_LV_NUM1.
  " P_GT_ITAB테이블을 LOOP으로 돌면서 CARRID가 'AA'인 것을 'ZZ'로 바꾼다.
  " 메인테이블로 돌아갔을 때 GT_ITAB에서 'AA'였던 데이터들은 'ZZ'로 바뀌는 걸 확인할 수 있다.
  LOOP AT P_GT_ITAB INTO GS_ITAB.
    IF GS_ITAB-CARRID EQ 'AA'.
      GS_ITAB-CARRID = 'ZZ'.
      MODIFY P_GT_ITAB FROM GS_ITAB.
    ENDIF.
  ENDLOOP.
ENDFORM.

실행화면 - CARRID(Airline Code)가 'AA'부터 'LH'까지 인 데이터들을 보여준다.
* CARRID가 'AA'의 데이터들은 ''ZZ'로 바뀐 것을 확인할 수 있다!