Modularization Part 6: Methods and Local Classes
Write your first classes for modularization: class definition and implementation, instance vs static methods, attributes, constructors, calling methods, and how a class replaces FORM-based report logic.
Explanation
📌 KEY POINTS
✅ A class has a DEFINITION (what) and an IMPLEMENTATION (how).
✅ Static methods (CLASS-METHODS) are called via class=>method; instance methods via object->method after creating an object.
✅ Visibility sections PUBLIC / PROTECTED / PRIVATE hide internal details.
💡 For report logic, one local class with small methods is the modern replacement for FORM routines.
━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE
Parts 1–5 covered classic units. Classes are the modern way to modularize — this part is the practical introduction; the OOP ABAP topic goes deeper (inheritance, interfaces, polymorphism).
━━━━━━━━━━━━━━━━━━━━
▶ 1. DEFINITION AND IMPLEMENTATION
CLASS lcl_flight_service DEFINITION.
PUBLIC SECTION.
METHODS constructor IMPORTING iv_carrid TYPE s_carr_id.
METHODS get_flights RETURNING VALUE(rt_flights) TYPE ty_flights.
PRIVATE SECTION.
DATA mv_carrid TYPE s_carr_id.
ENDCLASS.
CLASS lcl_flight_service IMPLEMENTATION.
METHOD constructor. mv_carrid = iv_carrid. ENDMETHOD.
METHOD get_flights. SELECT … WHERE carrid = mv_carrid. ENDMETHOD.
ENDCLASS.
━━━━━━━━━━━━━━━━━━━━
▶ 2. INSTANCE VS STATIC
- Instance: each object has its own attributes (mv_carrid). Create with CREATE OBJECT lo_service EXPORTING iv_carrid = 'LH'. or NEW lcl_flight_service( 'LH' ).
- Static: CLASS-METHODS / CLASS-DATA, one per class. Good for stateless helpers (conversions, calculations).
- Use instance methods when the object holds state or must be replaceable in tests.
━━━━━━━━━━━━━━━━━━━━
▶ 3. CALLING METHODS
- Classic: CALL METHOD lo_service->get_flights RECEIVING rt_flights = lt_flights.
- Modern functional: lt_flights = lo_service->get_flights( ).
- With several parameters: lo->m( EXPORTING a = 1 IMPORTING b = lv_b ).
━━━━━━━━━━━━━━━━━━━━
▶ 4. CONSTRUCTORS
- constructor — runs when an object is created; initializes attributes.
- class_constructor — runs once before first use of the class (static initialization).
━━━━━━━━━━━━━━━━━━━━
▶ 5. ATTRIBUTES AND NAMING
Common prefixes: mv_/mt_ (member variable/table), gv_ for globals, iv_/ev_/cv_/rv_ for parameters. Follow your team's convention.
━━━━━━━━━━━━━━━━━━━━
▶ 6. FROM FORMS TO A CLASS
Each FORM becomes a method; global variables become private attributes or parameters; START-OF-SELECTION creates the object and calls run( ).
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
Run the code example: a local flight service class with constructor, instance method, static helper and functional calls.
✅ CHECKPOINT: you can build and use a simple class instead of FORM routines.
Code example
REPORT zmod_part6. TYPES ty_flights TYPE STANDARD TABLE OF sflight. PARAMETERS p_carr TYPE s_carr_id DEFAULT 'LH'. *---------------------------------------------------------------------*CLASS lcl_flight_service DEFINITION. PUBLIC SECTION. METHODS constructor IMPORTING iv_carrid TYPE s_carr_id. METHODS get_flights RETURNING VALUE(rt_flights) TYPE ty_flights. METHODS count_full RETURNING VALUE(rv_count) TYPE i. CLASS-METHODS free_seats " static helper, stateless IMPORTING is_flight TYPE sflight RETURNING VALUE(rv_free) TYPE i. PRIVATE SECTION. DATA mv_carrid TYPE s_carr_id. " instance attribute DATA mt_flights TYPE ty_flights. " cached dataENDCLASS. CLASS lcl_flight_service IMPLEMENTATION. METHOD constructor. mv_carrid = iv_carrid. ENDMETHOD. METHOD get_flights. IF mt_flights IS INITIAL. " read once per object SELECT * FROM sflight INTO TABLE mt_flights WHERE carrid = mv_carrid. ENDIF. rt_flights = mt_flights. ENDMETHOD. METHOD count_full. DATA: lt_flights TYPE ty_flights, ls_flight TYPE sflight, lv_free TYPE i. lt_flights = get_flights( ). LOOP AT lt_flights INTO ls_flight. lv_free = free_seats( ls_flight ). IF lv_free <= 0. rv_count = rv_count + 1. ENDIF. ENDLOOP. ENDMETHOD. METHOD free_seats. rv_free = is_flight-seatsmax - is_flight-seatsocc. ENDMETHOD.ENDCLASS. *---------------------------------------------------------------------*DATA: go_service TYPE REF TO lcl_flight_service, gt_flights TYPE ty_flights, gs_first TYPE sflight, gv_full TYPE i, gv_free TYPE i. START-OF-SELECTION.* ===== Step 1: create the object ===== CREATE OBJECT go_service EXPORTING iv_carrid = p_carr. * ===== Step 2: instance method calls ===== CALL METHOD go_service->get_flights RECEIVING rt_flights = gt_flights. gv_full = go_service->count_full( ). " functional call, same result WRITE: / 'full flights:', gv_full. * ===== Step 3: static method call ===== READ TABLE gt_flights INTO gs_first INDEX 1. IF sy-subrc = 0. CALL METHOD lcl_flight_service=>free_seats EXPORTING is_flight = gs_first RECEIVING rv_free = gv_free. WRITE: / 'free seats on first flight:', gv_free. ENDIF. * 💡 Modern syntax (7.40+): DATA(lo) = NEW lcl_flight_service( p_carr ).* LOOP AT get_flights( ) INTO DATA(ls_flight).Real project scenario
A team's reports used dozens of FORM routines sharing global tables. When two reports needed the same "flight availability" logic, it was copied, and the copies drifted apart.
They moved the logic into a small global class ZCL_FLIGHT_SERVICE with instance methods for data access and static helpers for calculations. Both reports used the same class; a later rule change was made once and verified with unit tests.
Common mistakes
- Making everything static even when state or test replacement is needed.
- Public attributes that anyone can change.
- Huge methods that are just FORMs renamed.
- Forgetting to create the object before calling instance methods (null reference dump).
- Mixing CALL METHOD and functional style inconsistently.
Best practices
- Small methods with clear parameters.
- Private attributes, public methods.
- Static methods for stateless helpers; instances for stateful services.
- Functional call style for readability.
- Constructors to initialize required state.
Interview angle
Questions: "Instance vs static method?", "What is a constructor?", "How do you replace FORMs with classes?"
Strong answer: instance methods work on an object's attributes and need an object (CREATE OBJECT/NEW), static methods belong to the class (class=>method) and suit stateless helpers; constructor initializes objects, class_constructor the class; replace FORMs by methods of a local class with parameters and private attributes, calling run( ) from START-OF-SELECTION.
Practice this lesson
Quick check
1. What is the difference between a static method and an instance method?
2. Why should a new validator class receive its database access object through the constructor?
3. Which is best for new S/4HANA code?
Interview questions
1. Where would you put business logic that must be reused by a report, a Fiori app and a BAPI?
Answer it in your own words first, then compare.
2. Customer validation exists separately in three reports and one OData service. How do you move it into a class-based design?
Answer it in your own words first, then compare.
Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.
More lessons in this topic
- Modularization Part 1: Why and How to Split ABAP Programs
- Modularization Part 10: Modularization for Unit Testing and Regression Safety
- Modularization Part 2: FORM Routines — Legacy but Still Important
- Modularization Part 3: FORM vs Method vs Function Module
- Modularization Part 4: Function Modules and Function Groups
- Modularization Part 5: Update Function Modules and IN UPDATE TASK
- Modularization Part 7: Global Classes vs Local Classes
- Modularization Part 8: Parameter Passing — IMPORTING, EXPORTING, CHANGING and RETURNING