본문 바로가기
IT/SAP

[ABAP] Object-Oriented Programing

by 109 2025. 8. 28.

ABAP OOB 완벽 가이드: 클래스 기반 ALV를 마스터하자

1. 서론: 왜 아직도 OOB를 배워야 하는가?

ABAP 개발자라면 한 번쯤은 REUSE_ALV_GRID_DISPLAY 함수 모듈을 사용해봤을 겁니다. 간편하지만 한계가 명확했던 이 방식은 cl_gui_alv_grid로 진화했고, 이제는 OOB(Object-Oriented Bridge) 방식의 cl_salv_table 클래스가 대세로 자리 잡았습니다.

REUSE_ALV_GRID_DISPLAY로 대표되는 절차 지향 프로그래밍은 데이터와 로직이 분리되어 있어 코드가 길어지고 유지보수가 어려워질 수 있습니다. 반면 OOB는 데이터와 로직을 하나의 객체로 캡슐화하여 모듈화되고 재사용 가능한 코드를 만듭니다. OOB는 단순히 ALV를 표시하는 기술을 넘어, 현대적인 객체 지향 개발 철학을 ABAP에 적용하는 첫걸음입니다.

이 글은 OOB가 무엇인지, 왜 사용해야 하는지, 그리고 자동차 정보를 예시로 실제 구현하는 방법까지 A부터 Z까지 알려드립니다. 기존 ALV 함수 모듈에 익숙한 분들도 이 글을 통해 객체 지향 기반의 현대적인 ABAP 개발 방식을 익힐 수 있을 것입니다.

2. ABAP 객체 지향 프로그래밍 기초 다지기

OOB는 ABAP 객체 지향(OO) 프로그래밍의 연장선에 있습니다. OOB를 제대로 이해하기 위해서는 몇 가지 핵심 개념을 알아야 합니다.

  • 클래스와 객체: 클래스는 객체를 만들기 위한 이며, 객체는 그 틀을 통해 만들어진 실제 인스턴스입니다. ABAP에서는 CLASS ... DEFINITION으로 클래스 구조를 정의하고, CLASS ... IMPLEMENTATION으로 메소드 코드를 구현합니다.
  • 상속(Inheritance): INHERITING FROM 구문을 통해 기존 클래스의 속성과 메소드를 물려받아 기능을 확장할 수 있습니다.
  • 인터페이스(Interface): INTERFACES를 통해 구현해야 할 기능의 규약을 정의합니다. 인터페이스를 구현하는 모든 클래스는 동일한 메소드를 가져야 합니다.
  • 속성(Attribute)과 메소드(Method): 속성은 클래스의 데이터를, 메소드는 클래스의 동작을 정의합니다.
    • Static vs. Instance: CLASS-DATACLASS-METHODS는 객체 생성 없이 클래스 자체에 소속되며, DATAMETHODS는 객체가 생성될 때마다 개별적으로 존재합니다.
  • 객체 참조: REF TO는 객체를 가리키는 포인터 역할을 하며, CREATE OBJECT로 실제 객체를 생성하여 참조 변수에 할당합니다.

3. OOB의 핵심 개념과 기본 구조

OOB의 핵심은 바로 cl_salv_table 클래스입니다. 이 클래스는 화면(UI)을 구성하는 역할과 데이터(ITAB)를 관리하는 역할을 분리합니다.

  • OOB의 역할: Bridge(다리) 패턴을 통해 데이터 모델과 뷰를 분리합니다. 개발자는 데이터를 처리하는 로직과 ALV를 화면에 표시하는 로직을 독립적으로 다룰 수 있어 코드가 깔끔해집니다.
  • cl_salv_table 클래스: OOB의 중심 클래스로, 모든 ALV 기능(정렬, 필터, 이벤트 등)을 객체 지향적으로 다룰 수 있는 메소드를 제공합니다.
  • 기본적인 사용법: cl_salv_tableFACTORY 메소드를 통해 인스턴스를 생성합니다. 이 메소드는 객체 생성과 데이터 바인딩을 한 번에 처리해줍니다.

4. cl_salv_table을 활용한 OOB의 장점

cl_salv_table은 기존 ALV 방식과 비교해 여러 장점을 제공합니다.

  • 객체 지향적 접근: 데이터, ALV 기능, 이벤트 등 모든 요소를 객체로 다루기 때문에 재사용성이 높고, 유지보수와 확장이 용이합니다.
  • 간결한 코드: 복잡한 구조체(예: it_fieldcat)를 선언하고 값을 채우는 대신, 메소드 체이닝 방식을 활용해 코드가 훨씬 직관적이고 줄어듭니다.
  • 풍부한 기능: get_columns(), get_filters() 등 간단한 메소드 호출만으로도 다양한 ALV 기능을 구현할 수 있습니다.

5. OOB 실제 구현 예시: 자동차 리포트 만들기

이제 간단한 자동차 리포트를 만들며 OOB의 실제 사용법을 알아봅시다.

  • 단계 1: 데이터 선언: 자동차 정보를 담을 구조체와 내부 테이블을 선언합니다.
TYPES: BEGIN OF ty_car,
         maker  TYPE string,
         model  TYPE string,
         color  TYPE string,
         speed  TYPE i,
       END OF ty_car.

DATA: lt_cars TYPE TABLE OF ty_car.
  • 단계 2: OOB 인스턴스 생성: cl_salv_table=>factory() 메소드를 호출하여 객체를 생성합니다.
DATA: lo_alv TYPE REF TO cl_salv_table.

CALL METHOD cl_salv_table=>factory
  IMPORTING
    r_salv_table = lo_alv
  CHANGING
    t_table      = lt_cars.

IF lo_alv IS INITIAL.
  " Error Handling
ENDIF.
  • 단계 3: 데이터 바인딩: FACTORY 메소드가 이미 내부 테이블을 바인딩해줍니다. 이제 데이터를 채워 넣습니다.
  • 단계 4: 기능 추가: display() 호출 전에 원하는 기능을 설정합니다.
DATA: lo_columns   TYPE REF TO cl_salv_columns_table,
      lo_sorts     TYPE REF TO cl_salv_sorts,
      lo_functions TYPE REF TO cl_salv_functions.

" 컬럼 설정
lo_columns = lo_alv->get_columns( ).
CALL METHOD lo_columns->set_column_position
  EXPORTING
    columnname = 'SPEED'
    position   = 1.

" 정렬 기능 추가
lo_sorts = lo_alv->get_sorts( ).
CALL METHOD lo_sorts->add_sort
  EXPORTING
    columnname = 'SPEED'
    position   = 1.

" 툴바 버튼 추가
lo_functions = lo_alv->get_functions( ).
CALL METHOD lo_functions->add_function
  EXPORTING
    name    = 'ALL_CARS'
    icon    = icon_display
    tooltip = '전체 자동차 정보 조회'
    text    = '전체 조회'.
  • 단계 5: 화면 출력: 마지막으로 display() 메소드를 호출하여 ALV를 화면에 표시합니다.
CALL METHOD lo_alv->display.

6. 이벤트 핸들링: 사용자 인터랙션 추가하기

ALV에서 사용자의 더블 클릭이나 링크 클릭에 반응하려면 이벤트를 다뤄야 합니다. 이벤트 핸들링은 OOB의 핵심적인 기능으로, 특정 동작이 발생했을 때 미리 정의해 둔 로직을 실행하도록 하는 것입니다.

  • 이벤트 클래스: OOB 이벤트는 cl_salv_events_table 클래스를 통해 관리됩니다. 이 클래스에는 ALV에서 발생하는 다양한 이벤트(더블 클릭, 링크 클릭 등)가 메소드로 정의되어 있습니다.
  • 이벤트 핸들러 클래스 생성: 이벤트를 처리할 메소드를 가진 로컬 클래스를 정의합니다. FOR EVENT 구문은 특정 클래스의 이벤트를 처리할 메소드를 지정하는 역할을 합니다.
CLASS lcl_event_handler DEFINITION.
  PUBLIC SECTION.
    METHODS: handle_double_click
             FOR EVENT double_click OF cl_salv_events_table
             IMPORTING
               row. " 'row' 파라미터로 더블 클릭된 행의 인덱스를 받음
ENDCLASS.

CLASS lcl_event_handler IMPLEMENTATION.
  METHOD handle_double_click.
    DATA: lv_index TYPE i.
    DATA: ls_car LIKE LINE OF lt_cars.

    " 더블 클릭된 행의 인덱스를 가져옴
    lv_index = row.

    " 해당 행의 데이터를 읽어옴
    READ TABLE lt_cars INDEX lv_index INTO ls_car.

    IF sy-subrc = 0.
      " 읽어온 데이터로 메시지 출력
      MESSAGE |The car you selected is { ls_car-model } by { ls_car-maker }| TYPE 'I'.
    ENDIF.
  ENDMETHOD.
ENDCLASS.
  • 이벤트 핸들러 등록: SET HANDLER 구문을 사용하여 객체를 이벤트와 연결합니다. 이 코드는 이벤트 핸들러(lo_handler)의 handle_double_click 메소드가 ALV 이벤트(lo_events)의 double_click 이벤트에 반응하도록 설정합니다.
DATA: lo_events   TYPE REF TO cl_salv_events_table,
      lo_handler  TYPE REF TO lcl_event_handler.

lo_events = lo_alv->get_event( ).
CREATE OBJECT lo_handler.
SET HANDLER lo_handler->handle_double_click FOR lo_events.

7. 심화 기능: 컬러 및 서식 적용

ALV의 시각적인 효과를 높이기 위해 셀이나 행에 색상을 입힐 수 있습니다.

  • 셀 서식 변경: lvc_s_scol 구조체를 이용해 특정 셀의 색상이나 스타일을 변경할 수 있습니다. 예를 들어, SPEED가 특정 값 이상인 자동차 행에 다른 색상을 지정할 수 있습니다.
  • 툴바 아이콘 추가: add_function 메소드에 아이콘 이름을 추가하여 툴바에 직관적인 버튼을 배치할 수 있습니다.

8. 결론: OOB, 이제 선택이 아닌 필수

cl_salv_table을 활용한 OOB 방식은 ABAP 개발 패러다임을 한 단계 끌어올렸습니다. 깔끔하고 재사용 가능한 코드, 그리고 객체 지향의 장점을 모두 누릴 수 있기 때문입니다. 이제 OOB는 새로운 ALV 리포트를 개발할 때 선택이 아닌 필수가 되었습니다.

직접 코드를 작성하고 기능을 하나씩 추가해보며 OOB의 강력함을 경험해보세요. 이 글이 여러분의 ABAP 개발 실력 향상에 큰 도움이 되기를 바랍니다.

9. 자바 개발자를 위한 한마디: ABAP OOB와 자바 OO의 차이점

자바에 익숙한 개발자라면 ABAP의 객체 지향 문법이 다소 생소하게 느껴질 수 있습니다. 하지만 핵심 개념은 동일하며, 몇 가지 문법적인 차이만 이해하면 쉽게 적응할 수 있습니다.

  • 클래스 정의와 구현의 분리: 자바는 하나의 클래스 파일(.java) 안에 정의와 구현이 모두 담겨 있지만, ABAP은 CLASS ... DEFINITIONCLASS ... IMPLEMENTATION으로 클래스의 선언과 로직 구현을 명확히 분리합니다. DEFINITION은 자바의 인터페이스처럼 클래스의 기능을 외부에 공개하는 역할을 하고, IMPLEMENTATION은 자바의 클래스 본문처럼 실제 동작 로직을 작성하는 곳입니다.
  • 다중 상속의 제한: 자바와 마찬가지로, ABAP도 단일 클래스 상속만 허용합니다. 즉, 하나의 클래스만 상속받을 수 있습니다. 하지만 INTERFACES 구문을 통해 다중 인터페이스 구현은 가능합니다. 이는 자바와 동일한 객체 지향 원칙으로, 코드의 복잡성을 낮추고 유연성을 확보하기 위한 디자인입니다.

클래스 생성 비교 예시

자바 (Java)

// 자바는 인터페이스를 통해 다형성을 구현합니다.
interface Vehicle {
    int getSpeed();
}

// 하나의 파일에 클래스 정의와 구현이 함께 존재
public class Car implements Vehicle {
    private String model;

    public void setModel(String model) {
        this.model = model;
    }
    
    public String getModel() {
        return this.model;
    }

    @Override
    public int getSpeed() {
        return 100; // 예시 속도
    }

    public static void main(String[] args) {
        // 클래스 인스턴스 생성 및 메소드 호출
        Car myCar = new Car();
        myCar.setModel("Sonata");
        System.out.println(myCar.getModel());

        // 인터페이스를 이용한 다형성
        Vehicle myVehicle = new Car();
        System.out.println(myVehicle.getSpeed());
    }
}


ABAP

* ABAP은 인터페이스를 통해 다형성을 구현합니다.
INTERFACE zif_vehicle.
  METHODS: get_speed RETURNING VALUE(rv_speed) TYPE i.
ENDINTERFACE.


* 클래스 정의와 구현이 분리
CLASS lcl_car DEFINITION.
  PUBLIC SECTION.
    INTERFACES: zif_vehicle.
    DATA: model TYPE string.
    METHODS: set_model IMPORTING iv_model TYPE string,
             get_model RETURNING VALUE(rv_model) TYPE string.
ENDCLASS.

CLASS lcl_car IMPLEMENTATION.
  METHOD set_model.
    me->model = iv_model.
  ENDMETHOD.

  METHOD get_model.
    rv_model = me->model.
  ENDMETHOD.

  METHOD zif_vehicle~get_speed.
    rv_speed = 100. " 예시 속도
  ENDMETHOD.
ENDCLASS.

* 프로그램 메인 루틴
DATA: lo_car TYPE REF TO lcl_car.
CREATE OBJECT lo_car.

CALL METHOD lo_car->set_model
  EXPORTING
    iv_model = 'Sonata'.

DATA: lv_model TYPE string.
lv_model = lo_car->get_model( ).
WRITE: lv_model.

DATA: lo_vehicle TYPE REF TO zif_vehicle.
lo_vehicle = lo_car. " 다형성

DATA: lv_speed TYPE i.
lv_speed = lo_vehicle->get_speed( ).
WRITE: / lv_speed.


 

 

출저:

What is Object Orientation?