ABAP CLASS y METHOD: Programacion orientada a objetos

Kategorie
ABAP-Statements
Veröffentlicht
Autor
Johannes

La sentencia CLASS es el fundamento de la programacion orientada a objetos (POO) en ABAP. Con clases puedes agrupar datos (atributos) y funciones (metodos) en unidades reutilizables.

Concepto basico

Una clase es una plantilla (blueprint) para objetos. Define:

  • Atributos: Variables que almacenan el estado de un objeto
  • Metodos: Funciones que definen el comportamiento de un objeto

Un objeto es una instancia concreta de una clase.

Sintaxis

Definicion de clase

CLASS <nombre_clase> DEFINITION.
PUBLIC SECTION.
" Elementos accesibles publicamente
DATA: <atributo> TYPE <tipo>.
METHODS: <metodo> [IMPORTING/EXPORTING/RETURNING ...].
PROTECTED SECTION.
" Solo accesible para esta clase y subclases
PRIVATE SECTION.
" Solo accesible dentro de esta clase
ENDCLASS.

Implementacion de clase

CLASS <nombre_clase> IMPLEMENTATION.
METHOD <metodo>.
" Logica del metodo
ENDMETHOD.
ENDCLASS.

Areas de visibilidad

AreaAcceso
PUBLICAccesible desde cualquier lugar
PROTECTEDSolo la clase misma y subclases
PRIVATESolo dentro de la clase

Ejemplos

1. Definir y usar una clase simple

" Definicion
CLASS lcl_counter DEFINITION.
PUBLIC SECTION.
METHODS: increment,
get_value RETURNING VALUE(rv_value) TYPE i.
PRIVATE SECTION.
DATA: mv_count TYPE i VALUE 0.
ENDCLASS.
" Implementacion
CLASS lcl_counter IMPLEMENTATION.
METHOD increment.
mv_count = mv_count + 1.
ENDMETHOD.
METHOD get_value.
rv_value = mv_count.
ENDMETHOD.
ENDCLASS.
" Uso
START-OF-SELECTION.
DATA: lo_counter TYPE REF TO lcl_counter.
" Crear objeto
CREATE OBJECT lo_counter.
" O moderno: lo_counter = NEW #( ).
lo_counter->increment( ).
lo_counter->increment( ).
WRITE: / 'Contador:', lo_counter->get_value( ).
" Salida: Contador: 2

2. Clase con constructor

El constructor es un metodo especial que se llama automaticamente al crear un objeto:

CLASS lcl_person DEFINITION.
PUBLIC SECTION.
METHODS: constructor IMPORTING iv_name TYPE string
iv_age TYPE i,
get_info RETURNING VALUE(rv_info) TYPE string.
PRIVATE SECTION.
DATA: mv_name TYPE string,
mv_age TYPE i.
ENDCLASS.
CLASS lcl_person IMPLEMENTATION.
METHOD constructor.
mv_name = iv_name.
mv_age = iv_age.
ENDMETHOD.
METHOD get_info.
rv_info = |{ mv_name } tiene { mv_age } anos.|.
ENDMETHOD.
ENDCLASS.
" Uso
DATA: lo_person TYPE REF TO lcl_person.
" Crear objeto con parametros del constructor
lo_person = NEW #( iv_name = 'Max Muller' iv_age = 30 ).
WRITE: / lo_person->get_info( ).
" Salida: Max Muller tiene 30 anos.

3. Metodos con parametros

CLASS lcl_calculator DEFINITION.
PUBLIC SECTION.
METHODS: add IMPORTING iv_a TYPE i
iv_b TYPE i
RETURNING VALUE(rv_result) TYPE i,
divide IMPORTING iv_dividend TYPE i
iv_divisor TYPE i
EXPORTING ev_result TYPE f
RAISING cx_sy_zerodivide.
ENDCLASS.
CLASS lcl_calculator IMPLEMENTATION.
METHOD add.
rv_result = iv_a + iv_b.
ENDMETHOD.
METHOD divide.
IF iv_divisor = 0.
RAISE EXCEPTION TYPE cx_sy_zerodivide.
ENDIF.
ev_result = iv_dividend / iv_divisor.
ENDMETHOD.
ENDCLASS.
" Uso
DATA: lo_calc TYPE REF TO lcl_calculator,
lv_sum TYPE i,
lv_quot TYPE f.
lo_calc = NEW #( ).
" Parametro RETURNING: Metodo funcional
lv_sum = lo_calc->add( iv_a = 5 iv_b = 3 ).
WRITE: / 'Suma:', lv_sum.
" Parametro EXPORTING
lo_calc->divide( EXPORTING iv_dividend = 10
iv_divisor = 4
IMPORTING ev_result = lv_quot ).
WRITE: / 'Cociente:', lv_quot.

4. Metodos y atributos estaticos (CLASS-DATA/CLASS-METHODS)

Los elementos estaticos pertenecen a la clase misma, no a objetos individuales:

CLASS lcl_id_generator DEFINITION.
PUBLIC SECTION.
CLASS-METHODS: get_next_id RETURNING VALUE(rv_id) TYPE i.
PRIVATE SECTION.
CLASS-DATA: gv_counter TYPE i VALUE 0.
ENDCLASS.
CLASS lcl_id_generator IMPLEMENTATION.
METHOD get_next_id.
gv_counter = gv_counter + 1.
rv_id = gv_counter.
ENDMETHOD.
ENDCLASS.
" Uso - no se necesita objeto!
DATA: lv_id1 TYPE i,
lv_id2 TYPE i.
lv_id1 = lcl_id_generator=>get_next_id( ). " => para llamada estatica
lv_id2 = lcl_id_generator=>get_next_id( ).
WRITE: / 'ID 1:', lv_id1. " 1
WRITE: / 'ID 2:', lv_id2. " 2

5. Herencia

Con INHERITING FROM una clase puede heredar de otra:

" Clase base
CLASS lcl_vehicle DEFINITION.
PUBLIC SECTION.
METHODS: constructor IMPORTING iv_brand TYPE string,
get_brand RETURNING VALUE(rv_brand) TYPE string.
PROTECTED SECTION.
DATA: mv_brand TYPE string.
ENDCLASS.
CLASS lcl_vehicle IMPLEMENTATION.
METHOD constructor.
mv_brand = iv_brand.
ENDMETHOD.
METHOD get_brand.
rv_brand = mv_brand.
ENDMETHOD.
ENDCLASS.
" Clase derivada
CLASS lcl_car DEFINITION INHERITING FROM lcl_vehicle.
PUBLIC SECTION.
METHODS: constructor IMPORTING iv_brand TYPE string
iv_doors TYPE i,
get_info RETURNING VALUE(rv_info) TYPE string.
PRIVATE SECTION.
DATA: mv_doors TYPE i.
ENDCLASS.
CLASS lcl_car IMPLEMENTATION.
METHOD constructor.
" Llamar constructor de la clase padre
super->constructor( iv_brand = iv_brand ).
mv_doors = iv_doors.
ENDMETHOD.
METHOD get_info.
rv_info = |{ mv_brand } con { mv_doors } puertas|.
ENDMETHOD.
ENDCLASS.
" Uso
DATA: lo_car TYPE REF TO lcl_car.
lo_car = NEW #( iv_brand = 'BMW' iv_doors = 4 ).
WRITE: / lo_car->get_info( ).
" Salida: BMW con 4 puertas

6. Sobrescribir metodos (REDEFINITION)

CLASS lcl_animal DEFINITION.
PUBLIC SECTION.
METHODS: speak RETURNING VALUE(rv_sound) TYPE string.
ENDCLASS.
CLASS lcl_animal IMPLEMENTATION.
METHOD speak.
rv_sound = 'Sonido'.
ENDMETHOD.
ENDCLASS.
CLASS lcl_dog DEFINITION INHERITING FROM lcl_animal.
PUBLIC SECTION.
METHODS: speak REDEFINITION.
ENDCLASS.
CLASS lcl_dog IMPLEMENTATION.
METHOD speak.
rv_sound = 'Guau!'.
ENDMETHOD.
ENDCLASS.
" Uso
DATA: lo_animal TYPE REF TO lcl_animal,
lo_dog TYPE REF TO lcl_dog.
lo_animal = NEW lcl_animal( ).
lo_dog = NEW lcl_dog( ).
WRITE: / 'Animal:', lo_animal->speak( ). " Sonido
WRITE: / 'Perro:', lo_dog->speak( ). " Guau!

Tipos de parametros de metodos

TipoDescripcionSintaxis
IMPORTINGParametro de entradaIMPORTING iv_param TYPE tipo
EXPORTINGParametro de salidaEXPORTING ev_param TYPE tipo
CHANGINGEntrada y salidaCHANGING cv_param TYPE tipo
RETURNINGValor de retorno (funcional)RETURNING VALUE(rv_param) TYPE tipo
RAISINGExcepciones posiblesRAISING cx_exception

Creacion de objetos

DATA: lo_obj TYPE REF TO lcl_myclass.
" Sintaxis clasica
CREATE OBJECT lo_obj.
" Con parametros
CREATE OBJECT lo_obj
EXPORTING
iv_param = 'Valor'.
" Sintaxis moderna (desde 7.40)
lo_obj = NEW #( ).
lo_obj = NEW #( iv_param = 'Valor' ).
" Declaracion inline
DATA(lo_obj2) = NEW lcl_myclass( iv_param = 'Valor' ).

Clases globales vs. locales

TipoDefinicionUso
LocalEn el programa con CLASS ... DEFINITIONSolo en el mismo programa
GlobalEn el Class Builder (SE24)Disponible en todo el sistema

Las clases locales frecuentemente comienzan con lcl_ (local class), las globales con zcl_ o cl_.

Clases y metodos abstractos

Las clases abstractas no pueden ser instanciadas:

CLASS lcl_shape DEFINITION ABSTRACT.
PUBLIC SECTION.
METHODS: get_area ABSTRACT RETURNING VALUE(rv_area) TYPE f.
ENDCLASS.
CLASS lcl_rectangle DEFINITION INHERITING FROM lcl_shape.
PUBLIC SECTION.
METHODS: constructor IMPORTING iv_width TYPE f
iv_height TYPE f,
get_area REDEFINITION.
PRIVATE SECTION.
DATA: mv_width TYPE f,
mv_height TYPE f.
ENDCLASS.
CLASS lcl_rectangle IMPLEMENTATION.
METHOD constructor.
mv_width = iv_width.
mv_height = iv_height.
ENDMETHOD.
METHOD get_area.
rv_area = mv_width * mv_height.
ENDMETHOD.
ENDCLASS.

Notas importantes / Mejores practicas

  • Utiliza nombres descriptivos para clases y metodos.
  • Mantén los metodos cortos y enfocados (Single Responsibility).
  • Usa PRIVATE para datos internos, garantizando el encapsulamiento.
  • Parametros RETURNING permiten llamadas funcionales y encadenamiento.
  • Para comportamiento polimorfico usa INTERFACE en lugar de herencia.
  • Maneja errores con TRY...CATCH y excepciones.
  • Prefiere la sintaxis moderna NEW #( ) para creacion de objetos.
  • Las clases globales (SE24) son reutilizables y testeables.