본문 바로가기

ABAP 프로그래밍 개념/Object-Oriented ABAP

ABAP OOP : Polymorphism(다형성) PART5 : Interfaces

자바와 유사하게, ABAP Objects(객체)는 단일 상속(single inheritance)를 지원하고, C++ 처럼 다중 상속을 지원하지는 않습니다.

Single Inheritance의 의미는 클래스가 다양한 subclass를 가질 수있지만 하나의 Superclass를 가지는 것을 의미합니다. 많은 Subclass들은 그들의 Superclass를 자신과 같은 클래스로 사용할 수 있지만, 각각의 Sublcass들은 오직 하나의 Superclass만을 가지는 것을 의미합니다.

현대 프로그래밍 언어는 애매모호함을 피하기 위해서 Multiple Inheritance(많은 Superclass들을 가지는 것)를 지원하지는 않았습니다. Multiple Inheritance의 가장 일반적인 문제 중 하나는 diamond problem이라고 불리우는 것입니다. 예를들어 아래 그림을 봅시다.

슈퍼클래스 A 클래스를 상속하는 B, C 클래스가 있다고 볼 때, B와 C는 각각 A 클래스의 Method 1을 재정의 하였습니다. 그런데 클래스 D가 B와 C를 둘 다 상속하고 있다고 했을 때, 과연 D의 Method 1은 B와 C 중 어떤 것을 실행시켜야 할 까요?

이런 것을 피하기 위하여 Multiple Inheritance(다중 상속)을 가능하게 하는 한가지 방법은 Interfaces 입니다. Interfaces는 모든 위험문제를 피하면서 Multiple Inheritance의 이점을 취할 수 있도록 해줍니다.

Interfaces는 INTERFACE라는 구문으로 정의됩니다. Interface는 오직 Definition(정의)만을 포함하고, Implementation(구현)은 Interface를 사용하는 클래스에서 이뤄집니다. 만약 다양한 클래스에서 사용할 공통 정의를 만들고 싶다면, 그것을 Interface에서 만들면되고 다양한 클래스에서 그것을 사용하면 됩니다. Interface를 정의하는 것은 아래 구문과 같습니다.

if_student라는 Interface를 INTERFACE 구문을 통해 정의하고 그것을 ENDINTERFACE로 종료하면 됩니다.

INTERFACE if_student.
 DATA course TYPE char10.
 METHODS meth1.
 EVENTS enrolled.
ENDINTERFACE.

CLASS cl_science DEFINITION.
 PUBLIC SECTION.
  INTERFACES if_student.
ENDCLASS.

CLASS cl_science IMPLEMENTATION.
 METHOD if_student~meth1.
 ENDMETHOD.
ENDCLASS.

Interface는 methods, attributes, events 등과 같은 class를 지원할 수 있는 모든 구성요소를 가질 수 있습니다. Interface에서는 이러한 구성요소들이 디폴트로 PUBLIC SECTION에 기술하게 되고, Interface 정의할 때 어떠한 Visibility 영역을 사용할 수 없습니다. Interface는 일반적으로 여러 클래스에서 사용하도록 만들어지기 때문에, Interface에서 Visibility를 통해 구현을 구분짓는 것이 아닌 Interface를 사용하는 각 클래스가 각각의 Private Section이나 Protected Section에서 자신의 구성요소를 구현하면서 클래스의 공통 인터페이스를 정의하는 것이 타당합니다. 만약 Interface가 클래스의 PRIVATE SECTION안에 포함될 수 있도록 허용된다면, Superclass와 Subclass가 각각 자신들의 PRIVATE SECTION에서 같은 Interface 구현을 진행했다면, 같은 대상에 대해 복수의 구현이 이뤄질 위험이 있습니다.

위 코드를 보면 클래스 cl_science는 interface if_student를 PUBLIC SECTION의 INTERFACES 구문을 통해 사용하였습니다. cl_science 클래스 실행부안에서, Interface if_student에서 정의된 method1을 실행합니다. 왜냐하면, meth1은 Interface안에서 정의되었지만 클래스(cl_science)자체에 속한 것은 아니기 때문에, 이러한 클래스에서 인터페이스의 구성요소를 사용할 때는, interface_name(인터페이스 이름)~component_name(구성요소 이름)을 구문으로 사용합니다. '~'라는 부호는 interface의 구성요소에 접근하는데 사용하는 연산자입니다.

클래스와는 달리, Interface는 어떠한 implementation section(구현부)를 가지고 있지 않습니다. Interface는 프로그램의 global declaration area(전역선언부)에만 정의될 수 있고, 클래스, Procedure, Event Block에는 정의될 수 없습니다.

때때로, Interface의 네이밍은 꽤 길 수 있습니다. 긴 Interface 이름의 구성요소소에 접근하는 것을 피하기 위해서, Alias를 사용하여 쉽게 코딩할 수 있습니다. 예시는 아래와 같습니다.

INTERFACE if_student.

 DATA course TYPE char10.
 METHODS meth1.
 EVENTS enrolled.
 
ENDINTERFACE.

CLASS cl_science DEFINITION.
 PUBLIC SECTION.

 INTERFACES if_student.
 ALIASES m1 FOR if_student~meth1.
ENDCLASS.

CLASS cl_science IMPLEMENTATION.
 METHOD m1.
 
 ENDMETHOD.
ENDCLASS.

DATA science TYPE REF TO cl_science.

START-OF-SELECTION.

CREATE OBJECT science.
science->m1( ).

Interface는 INTERFACES 구문을 사용하여 Interface 안에 Interface를 넣어 Nested 하게 만들 수 있습니다.
아래 코드를 보면, if_studentif_college안에 포함되며 nested 하게 개발 되었습니다. Alias는 Interface if_college안에 속한 Interface인 if_student의 메소드 meth1을 위해 정의되었습니다. 클래스 cl_science는 Interface if_college을 실제 구현하여 실행합니다. Interface if_student의 메소드 meth1if_college안에서 정의된 alias를 사용하여 접근 가능합니다.

INTERFACE if_student.

DATA course TYPE char10.
 METHODS meth1.
 EVENTS enrolled.

ENDINTERFACE.

INTERFACE if_college.
 
 INTERFACES if_student.
 ALIASES m1 FOR if_student~meth1. 
 METHODS meth1.

ENDINTERFACE.

CLASS cl_science DEFINITION.
 PUBLIC SECTION.
  INTERFACES if_college.
  ALIASES m1 FOR if_college~m1.
  ALIASES m2 FOR if_college~meth1.
ENDCLASS.

CLASS cl_science IMPLEMENTATION. 
 METHOD m1.
 ENDMETHOD.

 METHOD m2.
 ENDMETHOD.
ENDCLASS.

DATA science TYPE REF TO cl_science.

START-OF-SELECTION.

CREATE OBJECT science.
science->m1( ).

Interaces의 수정은 Interface을 사용하는 모든 클래스에게 유효하지 않고 Interaces의 강화(hence)또한 피하는 것이 좋습니다.  객체 참조(interface를 언급한 클래스를 참조하는 객체)의 할당(assignment)을 인터페이스 참조(Interface를 업근한 객체)에 한다면 객체 참조가 인터페이스 참조보다 더 구체적이기(special)하기 때문에 narrow casting이 수행됩니다. 객체 참조가 interface 참조에 할당 된다면, 객체 참조를 사용하고 있는 클래스는 인터페이스 참조를 위해 사용될 인터페이스의 구현을 포함하고 있어야 합니다.

INTERFACE if_a1.
 METHODS meth1.
 ….
ENDINTERFACE.

CLASS cl_c1 DEFINITION.
PUBLIC SECTION.
INTERFACES if_a1.
METHODS meth2.
ENDCLASS.

CLASS cl_c1 IMPLEMENTATION.
 METHOD if_a1~meth1.
 ….
 ENDMETHOD.

 METHOD meth2.
 …
 ENDMETHOD.
ENDCLASS.

CLASS cl_c2 DEFINITION.
 PUBLIC SECTION.
  METHODS meth2.
ENDCLASS.
 
CLASS cl_c2 IMPLEMENTATION.
 METHOD meth2.
 …
 ENDMETHOD.
ENDCLASS.

DATA : o_if TYPE REF TO if_a1,
       o_cl1 TYPE REF TO cl_c1,
       o_cl2 TYPE REF TO cl_c2.

START-OF-SELECTION.

 CRETAE OBJECT : o_c11, o_cl2.

 O_if = o_cl1.
 O_if = o_cl2. ”Results in error.

 

위 예시에서 보면, 클래스 cl_c1if_al라는 Interface를 구현하고 있고, 그러므로 object reference(객체 참조 : 클래스를 참조)와 interface reference(인터페이스 참조 : 인터페이스를 참조) 간의 할당이 가능합니다. 그러나 클래스 cl_c2는 Interface reference(인터페이스 참조)에 할당될 수 없는데, 그 이유는 cl_c2는 인터페이스 if_al의 구현을 포함하고 있지 않기 때문입니다.

generic 프로그램을 만들때, 메소드의 파라미터로 Interace를 언급하는 것은 유용합니다. 그 이유는 interface를 언급한 어떠한 객체들로 Narrowing Cast를 수행할 수 있기 때문입니다. 객체의 dynamic type은 casting을 위해 고려되기 때문에, 정적 유형이 Interace를 구현하지 않은 경우, cast operator인 ?=을 사용하여 객체간의 Widening Cast를 수행할 수 있습니다.

Class Builder(SE24)에서 전역 Interface를 정의하는 프로세스는 클래스를 정의하는 것과 유사합니다.

그림 1. SE24

그림 1을 보면, Class Builder(SE24)에서 Interface 이름을 적고, Create 버튼을 누르면 됩니다. 단 만약, 이름이 ZIF로 시작을 한다면, Class Builder는 자동으로 Interface를 해당 이름으로 시작할 것입니다.(사전에 ZIF는 Interface 이름으로 만들 것이라고 SAP에 세팅되어 있음)

그림 2. Dialog Box

 그림 2를 보면, Dialog Box가 뜨며(ZIF란 이름이 아니므로) 클래스를 만들것인지, 인터페이스를 만들 것인지 입력할 수 있습니다.

그림 3. Interface 구현

위 그림과 같이, Interace도 클래스와 마찬가지로 같은 화면에서 Component에 대해서 각 Tab을 통해서 정의가 가능합니다. 정의 후에는 Activate를 진행합니다.

그림 4. Interface의 활용

그림 4와 같이, Class Builder에서 인터페이스 탭에 만든 인터페이스를 입력할수 있습니다.

그림 5. Alias 사용

Alias(별칭) Tab에서 인터페이스의 Component들에 대해서 클래스에서 어떤 별칭으로 사용할지 설정할 수 있고, 그것의 Visiblity까지 정의할 수 있습니다.

이것으로 기본적으로 Interface에 대해서 정의하여 보였고, 간단하게 만드는 방법까지 알아봤습니다.

반응형