ABAP OOP 실전 — CLASS, INTERFACE, INHERITANCE 완전 정복
1. 개요 - ABAP OOP가 왜 중요한가
SAP S/4HANA와 BTP(Business Technology Platform) 시대에 접어들면서, ABAP 개발은 더 이상 절차적 프로그래밍만으로는 충분하지 않습니다. RAP(RESTful ABAP Programming Model), Clean ABAP, ABAP Cloud 등 모던 ABAP 개발 패러다임은 모두 객체지향(OOP) 기반 위에 설계되어 있습니다.
이 튜토리얼에서는 ABAP OOP의 세 가지 핵심 축인 CLASS, INTERFACE, INHERITANCE를 체계적으로 다룹니다.
- CLASS의 선언부와 구현부 구조를 이해하고 직접 작성할 수 있다
- PUBLIC / PROTECTED / PRIVATE 가시성의 차이를 구분할 수 있다
- 생성자(constructor)와 정적 생성자(class_constructor)를 활용할 수 있다
- INHERITING FROM을 통한 상속과 메서드 재정의를 구현할 수 있다
- INTERFACE를 정의하고 다형성을 실무에 적용할 수 있다
- 업캐스트 / 다운캐스트의 원리와 안전한 사용법을 익힐 수 있다
학습 대상: ABAP 기본 문법(DATA, TYPES, SELECT 등)을 알고 있으며, 객체지향 개발로 전환하려는 ABAP 개발자. SAP S/4HANA 2021 이상 또는 SAP BTP ABAP Environment에서 실습할 수 있습니다.
2. CLASS 기본 구조 - 선언부와 구현부
ABAP 클래스는 크게 선언부(DEFINITION)와 구현부(IMPLEMENTATION)로 나뉩니다. 선언부에서는 클래스가 어떤 속성과 메서드를 가지는지 정의하고, 구현부에서는 메서드의 실제 로직을 작성합니다.
로컬 클래스 vs 글로벌 클래스
| 구분 | 로컬 클래스 | 글로벌 클래스 |
|---|---|---|
| 위치 | 프로그램/인클루드 내부 | SE24 또는 ADT에서 별도 생성 |
| 접근 범위 | 해당 프로그램 내에서만 | 시스템 전체에서 사용 가능 |
| 선언 키워드 | CLASS lcl DEFINITION. |
CLASS zcl DEFINITION PUBLIC. |
| 용도 | 테스트, 헬퍼, 로컬 로직 | 재사용 가능한 비즈니스 로직 |
로컬 클래스의 기본 구조는 다음과 같습니다.
CLASS lcl_calculator DEFINITION.
PUBLIC SECTION.
METHODS: add IMPORTING iv_a TYPE i
iv_b TYPE i
RETURNING VALUE(rv_result) TYPE i.
PRIVATE SECTION.
DATA: mv_last_result TYPE i.
ENDCLASS.
CLASS lcl_calculator IMPLEMENTATION.
METHOD add.
rv_result = iv_a + iv_b.
mv_last_result = rv_result.
ENDMETHOD.
ENDCLASS.
글로벌 클래스는 추가로 CREATE PUBLIC, FINAL, ABSTRACT 등의 옵션을 지정할 수 있습니다.
- FINAL - 이 클래스를 상속할 수 없도록 잠금
- CREATE PUBLIC / CREATE PROTECTED / CREATE PRIVATE - 누가 인스턴스를 생성할 수 있는지 제어
- ABSTRACT - 직접 인스턴스화 불가, 서브클래스를 통해서만 사용
핵심: 선언부(DEFINITION)는 "무엇을 할 수 있는가"를, 구현부(IMPLEMENTATION)는 "어떻게 하는가"를 담당합니다. 이 분리가 ABAP OOP의 기본 원칙입니다.
3. 가시성과 속성 - PUBLIC / PROTECTED / PRIVATE
클래스의 컴포넌트(속성, 메서드)는 가시성 섹션에 따라 접근 범위가 결정됩니다. 이것은 캡슐화(Encapsulation)의 핵심 메커니즘입니다.
| 섹션 | 클래스 내부 | 서브클래스 | 외부 호출자 | Friend |
|---|---|---|---|---|
| PUBLIC | O | O | O | O |
| PROTECTED | O | O | X | O |
| PRIVATE | O | X | X | O |
인스턴스 속성 vs 정적 속성
- 인스턴스 속성 (
DATA) - 각 객체마다 독립적으로 존재하는 데이터. 객체가 생성될 때마다 새로운 사본이 만들어집니다. - 정적 속성 (
CLASS-DATA) - 클래스 전체에서 공유하는 데이터. 모든 인스턴스가 동일한 값을 참조합니다. - 상수 (
CONSTANTS) - 변경 불가능한 고정 값. - READ-ONLY - PUBLIC SECTION에 선언 시 외부에서 읽기만 허용하고 쓰기는 차단합니다.
비유하자면, 인스턴스 속성은 "각 직원의 개인 사물함"이고, 정적 속성은 "부서 공용 게시판"과 같습니다. 모든 직원(인스턴스)이 각자의 사물함을 갖지만, 게시판은 부서(클래스) 하나에 하나만 존재합니다.
설계 원칙: 가능한 한 PRIVATE으로 선언하고, 필요한 것만 PUBLIC으로 노출하세요. "최소 권한 원칙"은 유지보수성과 안정성을 높여줍니다.
4. 메서드와 생성자
메서드는 클래스의 행위(Behavior)를 정의합니다. ABAP OOP에서는 인스턴스 메서드와 정적 메서드, 그리고 두 종류의 생성자를 구분해야 합니다.
파라미터 종류
| 키워드 | 방향 | 설명 |
|---|---|---|
IMPORTING |
입력 | 호출자가 메서드에 전달하는 값 |
EXPORTING |
출력 | 메서드가 호출자에게 반환하는 값 |
CHANGING |
입출력 | 전달받아 변경 후 반환 |
RETURNING |
반환 | 함수형 메서드, 메서드 체이닝에 필수 |
RAISING |
예외 | 발생 가능한 예외 클래스 선언 |
생성자(Constructor)
- 인스턴스 생성자 (
constructor) - 객체가 생성될 때마다 자동 호출됩니다.PUBLIC SECTION에 선언하며, IMPORTING 파라미터를 가질 수 있습니다. - 정적 생성자 (
class_constructor) - 클래스가 세션 내에서 최초로 사용될 때 단 1회만 호출됩니다. 파라미터를 가질 수 없습니다.
CLASS lcl_employee DEFINITION.
PUBLIC SECTION.
METHODS constructor IMPORTING iv_name TYPE string
iv_emp_id TYPE i.
CLASS-METHODS class_constructor.
METHODS get_info RETURNING VALUE(rv_info) TYPE string.
PRIVATE SECTION.
DATA: mv_name TYPE string,
mv_emp_id TYPE i.
CLASS-DATA: sv_counter TYPE i.
ENDCLASS.
CLASS lcl_employee IMPLEMENTATION.
METHOD class_constructor.
sv_counter = 0.
" 클래스 최초 사용 시 1회 실행 (예: 로그 초기화)
ENDMETHOD.
METHOD constructor.
mv_name = iv_name.
mv_emp_id = iv_emp_id.
sv_counter = sv_counter + 1.
ENDMETHOD.
METHOD get_info.
rv_info = |사원번호: { mv_emp_id } / 이름: { mv_name } / 전체 직원 수: { sv_counter }|.
ENDMETHOD.
ENDCLASS.
주의: class_constructor는 파라미터를 받을 수 없고, 반드시 PUBLIC SECTION에 선언해야 합니다. 정적 속성의 초기화나 환경 설정 로딩에 주로 사용됩니다.
5. 객체 생성과 사용 - NEW, ->, =>
ABAP 7.40 이후부터 NEW 연산자와 인라인 선언을 활용하여 간결하게 객체를 생성할 수 있습니다.
객체 생성 방법
" 방법 1: 전통적 방식
DATA lo_emp TYPE REF TO lcl_employee.
CREATE OBJECT lo_emp
EXPORTING iv_name = '김개발'
iv_emp_id = 1001.
" 방법 2: NEW 연산자 (ABAP 7.40+)
DATA lo_emp2 TYPE REF TO lcl_employee.
lo_emp2 = NEW #( iv_name = '박설계' iv_emp_id = 1002 ).
" 방법 3: 인라인 선언 + NEW (가장 간결)
DATA(lo_emp3) = NEW lcl_employee( iv_name = '이분석' iv_emp_id = 1003 ).
" 인스턴스 멤버 접근: -> 사용
DATA(lv_info) = lo_emp3->get_info( ).
" 정적 멤버 접근: => 사용
DATA(lv_count) = lcl_employee=>sv_counter.
self-reference: me
인스턴스 메서드 내부에서 me->를 통해 자기 자신의 속성이나 메서드를 명시적으로 참조할 수 있습니다. 로컬 변수와 인스턴스 속성의 이름이 동일할 때 구분하는 데 유용합니다.
메서드 체이닝
RETURNING 파라미터가 자기 자신의 레퍼런스를 반환하면, 메서드를 연속으로 호출하는 체이닝 패턴을 구현할 수 있습니다. 빌더(Builder) 패턴 등에서 자주 활용됩니다.
권장: 모던 ABAP 개발에서는NEW연산자와 인라인 선언을 사용하는 것이 일반적입니다.CREATE OBJECT는 레거시 코드에서 주로 볼 수 있습니다.
6. 상속(INHERITANCE) - 코드 재사용과 특화
상속은 기존 클래스(슈퍼클래스)의 속성과 메서드를 물려받아 새로운 클래스(서브클래스)를 만드는 메커니즘입니다. INHERITING FROM 키워드로 상속 관계를 선언합니다.
상속 규칙 요약
- 서브클래스는 슈퍼클래스의 PUBLIC 및 PROTECTED 컴포넌트를 상속받습니다
- PRIVATE 컴포넌트는 상속되지 않습니다 (friend 관계 제외)
- 메서드 재정의는 REDEFINITION 키워드를 사용합니다
- 재정의된 메서드에서 슈퍼클래스 원본 로직을 호출하려면 super->를 사용합니다
- 정적 메서드는 접근 가능하지만 재정의할 수 없습니다
- FINAL로 선언된 클래스는 상속할 수 없습니다
" 슈퍼클래스: 일반 문서
CLASS lcl_document DEFINITION.
PUBLIC SECTION.
METHODS constructor IMPORTING iv_title TYPE string.
METHODS get_description RETURNING VALUE(rv_desc) TYPE string.
PROTECTED SECTION.
DATA: mv_title TYPE string,
mv_created_at TYPE timestamp.
ENDCLASS.
CLASS lcl_document IMPLEMENTATION.
METHOD constructor.
mv_title = iv_title.
GET TIME STAMP FIELD mv_created_at.
ENDMETHOD.
METHOD get_description.
rv_desc = |문서: { mv_title }|.
ENDMETHOD.
ENDCLASS.
" 서브클래스: 승인 문서 (상속 + 확장)
CLASS lcl_approval_doc DEFINITION INHERITING FROM lcl_document.
PUBLIC SECTION.
METHODS constructor IMPORTING iv_title TYPE string
iv_approver TYPE string.
METHODS get_description REDEFINITION.
PRIVATE SECTION.
DATA: mv_approver TYPE string,
mv_status TYPE string VALUE 'PENDING'.
ENDCLASS.
CLASS lcl_approval_doc IMPLEMENTATION.
METHOD constructor.
super->constructor( iv_title = iv_title ). " 슈퍼클래스 생성자 호출 필수
mv_approver = iv_approver.
ENDMETHOD.
METHOD get_description.
rv_desc = |승인문서: { mv_title } / 승인자: { mv_approver } / 상태: { mv_status }|.
ENDMETHOD.
ENDCLASS.
" 사용 예시
DATA(lo_doc) = NEW lcl_approval_doc( iv_title = '구매요청서' iv_approver = '김부장' ).
DATA(lv_desc) = lo_doc->get_description( ).
" 결과: 승인문서: 구매요청서 / 승인자: 김부장 / 상태: PENDING
업캐스트와 다운캐스트
업캐스트(Upcast)는 서브클래스 레퍼런스를 슈퍼클래스 레퍼런스에 할당하는 것으로, 자동으로 수행됩니다. 반면 다운캐스트(Downcast)는 슈퍼클래스 레퍼런스를 서브클래스 레퍼런스로 변환하는 것이며, 반드시 CAST 연산자를 사용해야 합니다.
" 업캐스트: 서브 -> 슈퍼 (자동)
DATA lo_base TYPE REF TO lcl_document.
DATA(lo_approval) = NEW lcl_approval_doc( iv_title = '견적서' iv_approver = '이팀장' ).
lo_base = lo_approval. " 업캐스트 - 자동 변환
" 다운캐스트: 슈퍼 -> 서브 (명시적 CAST 필요)
TRY.
DATA(lo_back) = CAST lcl_approval_doc( lo_base ).
DATA(lv_info) = lo_back->get_description( ).
CATCH cx_sy_move_cast_error INTO DATA(lx_error).
" 캐스팅 실패 시 예외 처리
DATA(lv_msg) = lx_error->get_text( ).
ENDTRY.
" IS INSTANCE OF 로 안전한 타입 검사
IF lo_base IS INSTANCE OF lcl_approval_doc.
" 안전하게 다운캐스트 가능
ENDIF.
실무 팁: 다운캐스트 전에는 항상IS INSTANCE OF또는TRY-CATCH를 사용하세요. 런타임에CX_SY_MOVE_CAST_ERROR예외가 발생할 수 있습니다.
7. 인터페이스(INTERFACE) - 계약과 다형성
인터페이스는 "무엇을 해야 하는가"만 정의하고, "어떻게 하는가"는 구현 클래스에 맡기는 계약(Contract)입니다. ABAP 인터페이스의 주요 특징은 다음과 같습니다.
- 인터페이스 내부의 모든 컴포넌트는 PUBLIC입니다 (가시성 섹션이 없음)
- 속성(
DATA), 상수(CONSTANTS), 메서드(METHODS) 모두 선언 가능 - 하나의 클래스가 여러 인터페이스를 구현할 수 있어, 다중 상속의 한계를 극복
- 구현 클래스에서 인터페이스 컴포넌트는
intf~component형식으로 접근 - ALIASES로 별칭을 만들어 간결하게 사용 가능
" 인터페이스 정의
INTERFACE lif_printable.
METHODS print RETURNING VALUE(rv_output) TYPE string.
ENDINTERFACE.
INTERFACE lif_exportable.
METHODS export_to_csv RETURNING VALUE(rv_csv) TYPE string.
ENDINTERFACE.
" 두 개의 인터페이스를 동시에 구현하는 클래스
CLASS lcl_sales_order DEFINITION.
PUBLIC SECTION.
INTERFACES: lif_printable,
lif_exportable.
ALIASES print FOR lif_printable~print. " 별칭 설정
METHODS constructor IMPORTING iv_order_id TYPE string
iv_amount TYPE p.
PRIVATE SECTION.
DATA: mv_order_id TYPE string,
mv_amount TYPE p LENGTH 13 DECIMALS 2.
ENDCLASS.
CLASS lcl_sales_order IMPLEMENTATION.
METHOD constructor.
mv_order_id = iv_order_id.
mv_amount = iv_amount.
ENDMETHOD.
METHOD lif_printable~print.
rv_output = |주문번호: { mv_order_id } / 금액: { mv_amount }|.
ENDMETHOD.
METHOD lif_exportable~export_to_csv.
rv_csv = |{ mv_order_id };{ mv_amount }|.
ENDMETHOD.
ENDCLASS.
" 다형성 활용: 인터페이스 레퍼런스로 다양한 객체를 동일하게 처리
DATA lt_printables TYPE TABLE OF REF TO lif_printable.
DATA(lo_order1) = NEW lcl_sales_order( iv_order_id = 'SO-001' iv_amount = '15000.00' ).
DATA(lo_order2) = NEW lcl_sales_order( iv_order_id = 'SO-002' iv_amount = '28500.00' ).
APPEND lo_order1 TO lt_printables.
APPEND lo_order2 TO lt_printables.
LOOP AT lt_printables INTO DATA(lo_item).
DATA(lv_output) = lo_item->print( ).
WRITE: / lv_output.
ENDLOOP.
인터페이스 메서드 옵션
인터페이스를 구현하는 클래스에서 다음 옵션을 활용할 수 있습니다.
| 옵션 | 설명 |
|---|---|
ABSTRACT METHODS |
지정한 메서드를 추상으로 선언 (서브클래스에서 구현) |
ALL METHODS ABSTRACT |
인터페이스의 모든 메서드를 추상으로 설정 |
FINAL METHODS |
지정한 메서드를 재정의 불가로 잠금 |
DEFAULT IGNORE |
구현하지 않아도 에러 없이 무시 |
DEFAULT FAIL |
미구현 메서드 호출 시 런타임 에러 발생 |
상속 vs 인터페이스: 상속은 "A는 B의 한 종류다(IS-A)" 관계에, 인터페이스는 "A는 B를 할 수 있다(CAN-DO)" 관계에 적합합니다. 일반적으로 인터페이스를 먼저 고려하고, 코드 재사용이 필요할 때 상속을 추가하는 것이 권장됩니다.
8. 실무 활용 팁 - 설계 원칙과 실습 방법
설계 원칙
- 인터페이스 우선 설계 - 구체 클래스 대신 인터페이스에 의존하면 테스트와 교체가 용이합니다
- 생성자에서 초기화 - 객체 생성 시 필요한 의존성과 데이터를 constructor에서 주입하세요
- RETURNING 파라미터 활용 - 함수형 메서드로 작성하면 체이닝이 가능하고 코드가 간결해집니다
- 상속 깊이 제한 - 상속 계층이 3단계를 넘어가면 복잡도가 급격히 증가합니다. 구성(Composition)을 함께 검토하세요
- ABAP Unit으로 테스트 -
FOR TESTING키워드와 인터페이스 기반 모킹으로 단위 테스트를 작성하세요
SE24 / ADT에서 실습하기
- SE24 (Class Builder) - SAP GUI에서 글로벌 클래스를 시각적으로 생성하고 관리합니다. 메서드, 속성, 이벤트를 탭으로 관리할 수 있어 초보자에게 직관적입니다.
- ADT (ABAP Development Tools) - Eclipse 기반 개발 환경으로, 코드 기반으로 클래스를 작성합니다. Clean ABAP 스타일에 적합하며, S/4HANA 및 BTP 개발의 표준 도구입니다.
- ABAP 콘솔 앱 -
IF_OO_ADT_CLASSRUN~MAIN인터페이스를 구현하면 ADT에서 콘솔 출력으로 빠르게 테스트할 수 있습니다.
흔한 실수와 트러블슈팅
| 실수 | 원인 | 해결 |
|---|---|---|
super->constructor 미호출 |
서브클래스 constructor에서 슈퍼클래스 constructor를 빠뜨림 | 서브클래스 constructor의 첫 줄에서 반드시 super->constructor( ) 호출 |
CX_SY_MOVE_CAST_ERROR 덤프 |
다운캐스트 시 실제 타입과 불일치 | IS INSTANCE OF 또는 TRY-CATCH로 사전 검사 |
| 정적 메서드 REDEFINITION 시도 | 정적 메서드는 재정의 불가 | 인스턴스 메서드로 변경하거나, 서브클래스에서 동명의 새 정적 메서드 선언 |
| PRIVATE 속성 상속 기대 | PRIVATE은 서브클래스에서 접근 불가 | 서브클래스 접근이 필요하면 PROTECTED로 변경 |
| 인터페이스 메서드명 틸데(~) 누락 | lif~method 형식을 사용하지 않음 |
구현부에서 반드시 인터페이스명~메서드명 형식 사용, 또는 ALIASES 활용 |
FAQ:
- Q: ABSTRACT 클래스와 INTERFACE의 차이는? - ABSTRACT 클래스는 일부 메서드를 구현할 수 있지만, INTERFACE는 구현을 포함하지 않습니다. ABSTRACT 클래스는 단일 상속만 가능하고, INTERFACE는 여러 개를 동시에 구현할 수 있습니다.
- Q: class_constructor는 언제 실행되나요? - 해당 클래스가 세션 내에서 최초로 사용되는 시점(객체 생성, 정적 메서드 호출, 정적 속성 접근 등)에 자동으로 1회 실행됩니다.
- Q: 메서드 체이닝은 어떻게 구현하나요? - RETURNING 파라미터의 타입을 자기 자신의 클래스 레퍼런스(
REF TO)로 설정하고, 메서드 마지막에result = me를 반환합니다.
다음 단계 / 관련 주제
ABAP OOP의 기초를 익혔다면, 다음 주제로 학습을 확장할 수 있습니다.
- ABAP Unit 테스팅 - 인터페이스 기반 Test Double 작성과 자동화 테스트
- RAP (RESTful ABAP Programming Model) - S/4HANA 확장 및 BTP 개발의 표준 아키텍처
- Design Patterns in ABAP - Factory, Singleton, Observer 등 실무 패턴
- Clean ABAP - SAP 공식 코딩 가이드라인에 따른 읽기 좋은 코드 작성법
- ABAP Cloud - Released API만 사용하는 클라우드 개발 모델