ABAP INTERFACE: Interfaces for Polymorphic Programming

Category
ABAP-Statements
Published
Author
Johannes

An INTERFACE in ABAP defines a contract that classes must fulfill. It specifies which methods a class must provide, without specifying their implementation.

Basic Concept

  • An Interface only defines the signatures of methods (and optionally attributes/constants).
  • A Class implements the interface and provides the concrete logic.
  • Polymorphism: Different classes can implement the same interface, but react differently.

Syntax

Define Interface

INTERFACE <interfacename>.
METHODS: <method1> [IMPORTING/EXPORTING/RETURNING ...],
<method2> [...].
DATA: <attribute> TYPE <type>.
CONSTANTS: <constant> TYPE <type> VALUE <value>.
ENDINTERFACE.

Implement Interface in Class

CLASS <classname> DEFINITION.
PUBLIC SECTION.
INTERFACES: <interfacename>.
" Optional: Alias for interface methods
ALIASES: <alias> FOR <interfacename>~<method>.
ENDCLASS.
CLASS <classname> IMPLEMENTATION.
METHOD <interfacename>~<method>.
" Implementation
ENDMETHOD.
ENDCLASS.

Examples

1. Simple Interface

" Define interface
INTERFACE lif_printable.
METHODS: print RETURNING VALUE(rv_output) TYPE string.
ENDINTERFACE.
" Class 1: Document
CLASS lcl_document DEFINITION.
PUBLIC SECTION.
INTERFACES: lif_printable.
METHODS: constructor IMPORTING iv_title TYPE string.
PRIVATE SECTION.
DATA: mv_title TYPE string.
ENDCLASS.
CLASS lcl_document IMPLEMENTATION.
METHOD constructor.
mv_title = iv_title.
ENDMETHOD.
METHOD lif_printable~print.
rv_output = |Document: { mv_title }|.
ENDMETHOD.
ENDCLASS.
" Class 2: Invoice
CLASS lcl_invoice DEFINITION.
PUBLIC SECTION.
INTERFACES: lif_printable.
METHODS: constructor IMPORTING iv_number TYPE string
iv_amount TYPE p.
PRIVATE SECTION.
DATA: mv_number TYPE string,
mv_amount TYPE p DECIMALS 2.
ENDCLASS.
CLASS lcl_invoice IMPLEMENTATION.
METHOD constructor.
mv_number = iv_number.
mv_amount = iv_amount.
ENDMETHOD.
METHOD lif_printable~print.
rv_output = |Invoice { mv_number }: { mv_amount } EUR|.
ENDMETHOD.
ENDCLASS.
" Usage with polymorphism
DATA: lt_printables TYPE TABLE OF REF TO lif_printable,
lo_printable TYPE REF TO lif_printable.
" Different objects in one list
APPEND NEW lcl_document( 'Contract' ) TO lt_printables.
APPEND NEW lcl_invoice( iv_number = 'R-001' iv_amount = '1500.00' ) TO lt_printables.
" Treat all the same
LOOP AT lt_printables INTO lo_printable.
WRITE: / lo_printable->print( ).
ENDLOOP.
" Output:
" Document: Contract
" Invoice R-001: 1500.00 EUR

2. Interface with Alias

With ALIASES you can assign shorter names for interface methods:

INTERFACE lif_calculator.
METHODS: calculate IMPORTING iv_a TYPE i
iv_b TYPE i
RETURNING VALUE(rv_result) TYPE i.
ENDINTERFACE.
CLASS lcl_adder DEFINITION.
PUBLIC SECTION.
INTERFACES: lif_calculator.
" Alias for easier access
ALIASES: add FOR lif_calculator~calculate.
ENDCLASS.
CLASS lcl_adder IMPLEMENTATION.
METHOD lif_calculator~calculate.
rv_result = iv_a + iv_b.
ENDMETHOD.
ENDCLASS.
" Usage
DATA: lo_adder TYPE REF TO lcl_adder.
lo_adder = NEW #( ).
" With full name
DATA(lv_result1) = lo_adder->lif_calculator~calculate( iv_a = 5 iv_b = 3 ).
" With alias (shorter)
DATA(lv_result2) = lo_adder->add( iv_a = 5 iv_b = 3 ).

3. Implementing Multiple Interfaces

A class can implement multiple interfaces:

INTERFACE lif_serializable.
METHODS: to_json RETURNING VALUE(rv_json) TYPE string.
ENDINTERFACE.
INTERFACE lif_comparable.
METHODS: compare_to IMPORTING io_other TYPE REF TO lif_comparable
RETURNING VALUE(rv_result) TYPE i.
ENDINTERFACE.
CLASS lcl_product DEFINITION.
PUBLIC SECTION.
INTERFACES: lif_serializable,
lif_comparable.
METHODS: constructor IMPORTING iv_id TYPE i
iv_name TYPE string
iv_price TYPE p.
DATA: mv_id TYPE i READ-ONLY,
mv_name TYPE string READ-ONLY,
mv_price TYPE p DECIMALS 2 READ-ONLY.
ENDCLASS.
CLASS lcl_product IMPLEMENTATION.
METHOD constructor.
mv_id = iv_id.
mv_name = iv_name.
mv_price = iv_price.
ENDMETHOD.
METHOD lif_serializable~to_json.
rv_json = |{ "id": { mv_id }, "name": "{ mv_name }", "price": { mv_price } }|.
ENDMETHOD.
METHOD lif_comparable~compare_to.
DATA: lo_other TYPE REF TO lcl_product.
lo_other ?= io_other.
IF mv_price < lo_other->mv_price.
rv_result = -1.
ELSEIF mv_price > lo_other->mv_price.
rv_result = 1.
ELSE.
rv_result = 0.
ENDIF.
ENDMETHOD.
ENDCLASS.

4. Interface with Constants and Attributes

INTERFACE lif_status.
CONSTANTS: c_new TYPE i VALUE 1,
c_active TYPE i VALUE 2,
c_completed TYPE i VALUE 3,
c_cancelled TYPE i VALUE 4.
DATA: mv_current_status TYPE i.
METHODS: set_status IMPORTING iv_status TYPE i,
get_status RETURNING VALUE(rv_status) TYPE i.
ENDINTERFACE.
CLASS lcl_order DEFINITION.
PUBLIC SECTION.
INTERFACES: lif_status.
ENDCLASS.
CLASS lcl_order IMPLEMENTATION.
METHOD lif_status~set_status.
lif_status~mv_current_status = iv_status.
ENDMETHOD.
METHOD lif_status~get_status.
rv_status = lif_status~mv_current_status.
ENDMETHOD.
ENDCLASS.
" Using interface constants
DATA: lo_order TYPE REF TO lcl_order.
lo_order = NEW #( ).
lo_order->lif_status~set_status( lif_status=>c_active ).

5. Interface Inheritance (Composed Interface)

Interfaces can include other interfaces:

INTERFACE lif_readable.
METHODS: read RETURNING VALUE(rv_data) TYPE string.
ENDINTERFACE.
INTERFACE lif_writable.
METHODS: write IMPORTING iv_data TYPE string.
ENDINTERFACE.
" Composed interface
INTERFACE lif_read_write.
INTERFACES: lif_readable,
lif_writable.
METHODS: clear.
ENDINTERFACE.
" A class implementing lif_read_write
" must implement all methods from all three interfaces
CLASS lcl_buffer DEFINITION.
PUBLIC SECTION.
INTERFACES: lif_read_write.
PRIVATE SECTION.
DATA: mv_buffer TYPE string.
ENDCLASS.
CLASS lcl_buffer IMPLEMENTATION.
METHOD lif_readable~read.
rv_data = mv_buffer.
ENDMETHOD.
METHOD lif_writable~write.
mv_buffer = iv_data.
ENDMETHOD.
METHOD lif_read_write~clear.
CLEAR mv_buffer.
ENDMETHOD.
ENDCLASS.

6. Dependency Injection with Interfaces

Interfaces enable loose coupling and better testability:

" Interface for database access
INTERFACE lif_customer_repository.
METHODS: get_customer IMPORTING iv_id TYPE i
RETURNING VALUE(rs_customer) TYPE zcustomer
RAISING cx_not_found.
ENDINTERFACE.
" Production implementation
CLASS lcl_db_customer_repository DEFINITION.
PUBLIC SECTION.
INTERFACES: lif_customer_repository.
ENDCLASS.
CLASS lcl_db_customer_repository IMPLEMENTATION.
METHOD lif_customer_repository~get_customer.
SELECT SINGLE * FROM zcustomer
WHERE id = @iv_id
INTO @rs_customer.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_not_found.
ENDIF.
ENDMETHOD.
ENDCLASS.
" Mock for unit tests
CLASS lcl_mock_customer_repository DEFINITION.
PUBLIC SECTION.
INTERFACES: lif_customer_repository.
ENDCLASS.
CLASS lcl_mock_customer_repository IMPLEMENTATION.
METHOD lif_customer_repository~get_customer.
rs_customer = VALUE #( id = iv_id name = 'Test Customer' ).
ENDMETHOD.
ENDCLASS.
" Service uses the interface (not the concrete class)
CLASS lcl_customer_service DEFINITION.
PUBLIC SECTION.
METHODS: constructor IMPORTING io_repository TYPE REF TO lif_customer_repository,
get_customer_name IMPORTING iv_id TYPE i
RETURNING VALUE(rv_name) TYPE string.
PRIVATE SECTION.
DATA: mo_repository TYPE REF TO lif_customer_repository.
ENDCLASS.
CLASS lcl_customer_service IMPLEMENTATION.
METHOD constructor.
mo_repository = io_repository.
ENDMETHOD.
METHOD get_customer_name.
TRY.
DATA(ls_customer) = mo_repository->get_customer( iv_id ).
rv_name = ls_customer-name.
CATCH cx_not_found.
rv_name = 'Unknown'.
ENDTRY.
ENDMETHOD.
ENDCLASS.

Interface vs. Abstract Class

AspectInterfaceAbstract Class
Multiple inheritanceYes (multiple interfaces)No (only one parent class)
ImplementationNoneCan partially implement
AttributesYes (but uncommon)Yes
ConstructorNoYes
Use caseContracts, polymorphismShared base logic

Type Checking and Casting

DATA: lo_object TYPE REF TO object,
lo_printable TYPE REF TO lif_printable.
lo_object = NEW lcl_document( 'Test' ).
" Check if interface is implemented
IF lo_object IS INSTANCE OF lif_printable.
" Downcast to interface
lo_printable ?= lo_object.
WRITE: / lo_printable->print( ).
ENDIF.

Important Notes / Best Practice

  • Interfaces often start with lif_ (local) or zif_ / if_ (global).
  • Use interfaces for loose coupling and better testability.
  • Prefer interfaces over inheritance for polymorphism.
  • Keep interfaces small and focused (Interface Segregation Principle).
  • Use ALIASES for frequently used interface methods.
  • Interface constants are useful for status codes and enumerations.
  • Combine interfaces with TRY...CATCH for robust error handling.
  • Use CLASS for implementing interfaces.