Analizar y probar el código
Uso correcto de tipos de datos y conversiones de tipos
Campos de caracteres de procesamiento
Uso de la transferencia de código en ABAP SQL
Mejora del rendimiento de la tabla interna
Implementar verificaciones de autorización
Diseño de código orientado a objetos efectivo
Definir y trabajar con clases de excepción
Añadir documentación al código ABAP

Utilización de interfaces

Objective

After completing this lesson, you will be able to utilizar interfaces.

Uso de interfaz

Declarar una referencia de interfaz

Puede utilizar interfaces como un tipo de referencia para declarar una variable de referencia. Como que se ha indicado previamente, utilice las variables de referencia para crear y gestionar las instancias de una clase. Como no es posible instanciar una interfaz, es posible que desee saber qué clases de objetos puede gestionar mediante una referencia de interfaz.

Las referencias de interfaz pueden contener referencias a instancias de cualquier clase que implemente la interfaz de la misma manera que una variable de referencia con el tipo de una clase superior puede contener referencias a instancias de cualquier subclase. (Si ahora imagina que la clase superior es abstracta, tiene una situación idéntica de un tipo que no se puede instanciar manteniendo referencias a instancias de otras clases que están relacionadas con ella).

Al utilizar una variable con el tipo de una clase superior para gestionar una instancia de una de sus subclases, solo puede acceder a los componentes definidos en la clase superior. De forma similar, cuando utiliza una referencia de interfaz para gestionar una instancia de una clase que implementa la interfaz, solo puede acceder a los componentes definidos en la interfaz. Esto significa que el desarrollador de un framework concreto de clases puede enviar interfaces que proporcionan una vista particular de una clase en lugar de exponer cada cosa que puede hacer la clase.

Puede llamar a un método desde una interfaz utlizando una variable de referencia con el tipo de la clase. En este caso, debe utilizar el nombre completo del método (incluido el nombre de interfaz). Si ha definido un alias para el método, puede utilizarlo. Al llamar a un método de interfaz mediante una referencia de interfaz, el nombre de la interfaz se deduce del tipo de la variable de referencia y no es necesario especificar el nombre de interfaz antes del nombre del método.

Casting con referencias de interfaz

La asignación de referencias de objeto a una referencia de interfaz es también un cast; considera el objeto de alquiler o de transportista como si fuera una interlocutor comercial. Siempre puede asignar una instancia de la clase de implementación a una referencia de interfaz. Esto es un upcast, y está garantizado por el hecho de que una clase implementa la interfaz. Sin embargo, no puede asignar un objeto de una referencia de interfaz a una referencia con el tipo de clase de implementación, puesto que la verificación de sintaxis no puede determinar si los objetos de tiempo de ejecución reales serán compatibles. La asignación rental = partner funcionaría si el objeto en la referencia de interfaz es realmente una instancia de lcl_car_rent, pero si se trata de una instancia de otra clase de implementación, provocaría un error de tiempo de ejecución.

Aquí tenemos un downcast de la misma manera en que se ha producido en la herencia. La solución aquí es la misma. Si necesita asignar una referencia de objeto de una variable de referencia con el tipo de una interfaz a una con el tipo de una clase (para poder acceder a características específicas de la clase), debe utilizar el operador CAST. La solución correcta en este caso sería:

ABAP
123
IF partner IS INSTANCE OF lcl_car_rental. rental = CAST #( partner ). ENDIF.

Pruébelo: Uso de la interfaz

  1. Cree una clase nueva que implemente la interfaz IF_OO_ADT_CLASSRUN.
  2. Cambie a la pestaña Tipos locales y copie el siguiente fragmento de código en el editor:
    Code Snippet
    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
    INTERFACE lif_partner. METHODS get_partner_attributes. ENDINTERFACE. CLASS lcl_travel_Agency DEFINITION. PUBLIC SECTION. ENDCLASS. CLASS lcl_airline DEFINITION. PUBLIC SECTION. INTERFACES lif_Partner. TYPES: BEGIN OF ts_detail, name TYPE string, value TYPE string, END OF ts_detail, tt_Details TYPE SORTED TABLE OF ts_detail WITH UNIQUE KEY name. METHODS get_details RETURNING VALUE(rt_details) TYPE tt_details. ENDCLASS. CLASS lcl_car_Rental DEFINITION. PUBLIC SECTION. interfaces lif_Partner. TYPES: BEGIN OF ts_info, name TYPE c LENGTH 20, value TYPE c LENGTH 20, END OF ts_info, tt_Info TYPE SORTED TABLE OF ts_info WITH UNIQUE KEY name. METHODS get_information RETURNING VALUE(rt_details) TYPE tt_info. ENDCLASS. CLASS lcl_airline IMPLEMENTATION. METHOD get_details. ENDMETHOD. METHOD lif_partner~get_partner_attributes. ENDMETHOD. ENDCLASS. CLASS lcl_car_rental IMPLEMENTATION. METHOD get_information. ENDMETHOD. METHOD lif_partner~get_partner_attributes. ENDMETHOD. ENDCLASS.
  3. Cambie a la pestaña Clase global y pegue el siguiente fragmento de código en la implementación del método if_oo_adt_classrun~main( ).
    Code Snippet
    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
    CLASS zcl_s4d401_interfaces_2 DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun . PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_s4d401_interfaces_2 IMPLEMENTATION. METHOD if_oo_adt_classrun~main. DATA car_rental TYPE REF TO lcl_car_rental. DATA airline TYPE REF TO lcl_airline. DATA agency TYPE REF TO lcl_travel_agency. DATA partners TYPE TABLE OF REF TO lif_partner. agency = NEW #( ). car_rental = NEW #( iv_name = 'ABAP Autos' iv_contact_person = 'Mr Jones' iv_has_hgv = abap_true ). agency->add_partner( car_rental ). airline = NEW #( iv_name = 'Fly Happy' iv_contact_person = 'Ms Meyer' iv_city = 'Frankfurt' ). agency->add_partner( airline ). LOOP AT agency->get_partners( ) INTO DATA(partner). out->write( partner->get_partner_attributes( ) ). ENDLOOP. ENDMETHOD. ENDCLASS.

Llamar métodos de interfaz

En el ejercicio anterior, definió la interfaz LIF_OUTPUT y la implementó en las clases LCL_CARRIER y LCL_FLIGHT. En su clase global, el método get_output de la interfaz LIF_OUTPUT ya se llama para la instancia de transportista creada. En este ejercicio, ahora también llamará el método de interfaz get_output para las instancias de las clases LCL_PASSENGER_FLIGHT y LCL_CARGO_FLIGHT.

Modelo:

  • /LRN/CL_S4D401_OOS_INTERFACE (clase global)

Solución:

  • /LRN/CL_S4D401_OOS_INTF_USAGE (clase global)

Tarea 1: Copiar plantilla (opcional)

Copie la clase de modelo /LRN/CL_S4D401_OOS_INTERFACE. Si ha finalizado el ejercicio anterior, puede omitir esta tarea y continuar editando su clase ZCL_##_SOLUTION.

Pasos

  1. Copie la clase /LRN/CL_S4D401_OOS_INTERFACE en una clase de su propio paquete (nombre sugerido: ZCL_##_SOLUTION, donde ## representa su número de grupo).

    1. En el Explorador de proyectos, haga clic con el botón derecho en la clase /LRN/CL_S4D401_OOS_INTERFACE para abrir el menú contextual.

    2. En el menú contextual, seleccione Duplicar....

    3. Introduzca el nombre del paquete en el campo Paquete. En el campo Nombre, introduzca ZCL_##_SOLUTION, donde ## representa su número de grupo.

    4. Seleccione Siguiente.

    5. Confirme la orden de transporte y seleccione Finalizar.

  2. Active la copia.

    1. Pulse Ctrl + F3 para activar la clase.

Tarea 2: Utilizar la interfaz

En la clase local LCL_FLIGHT, modifique la visibilidad del método de instancia GET_DESCRIPTION para forzar a los usuarios externos a llamar el método GET_OUTPUT en su lugar. A continuación, ajuste la implementación del método IF_OO_ADT_CLASSRUN~MAIN según corresponda.

Pasos

  1. En la clase local LCL_FLIGHT, utilice una corrección rápida para modificar la visibilidad del método de instancia GET_DESCRIPTION a protegida.

    1. Navegue a la definición del método GET_DESCRIPTION en la clase local LCL_FLIGHT.

    2. En la sentencia METHODS, sitúe el cursor en get_description y pulse Ctrl + 1 para invocar las correcciones rápidas disponibles.

    3. En la lista de correcciones rápidas disponibles, seleccione Proteger get_description.

  2. Modifique la visibilidad de las redefiniciones de GET_DESCRIPTION en las subclases LCL_PASSENGER_FLIGHT y LCL_CARGO_FLIGHT.

    Nota

    Debe copiar las redefiniciones manualmente. Aún no hay una solución rápida para modificar la visibilidad de las redefiniciones.
    1. Navegue a la redefinición del método GET_DESCRIPTION en la clase local LCL_PASSENGER_FLIGHT.

    2. Seleccione la sentencia METHODS y pulse Ctrl + X.

    3. Sitúe el cursor en la siguiente fila después de la sentencia PROTECTED SECTION y pulse Ctrl + V.

    4. Repita esto en la clase local LCL_CARGO_FLGHT.

  3. Ajuste la implementación del método IF_OO_ADT_CLASSRUN~MAIN donde se llama el método GET_DESCRIPTION. Sustituya el método GET_DESCRIPTION por el método de interfaz GET_OUTPUT.

    Consejo

    Utilice los dos mensajes de error en la vista Problemas para navegar a los lugares en los que aún se llama el método GET_DESCRIPTION.
    1. Ajuste el código de la siguiente manera:

      ABAP
      123
      out->write( name = |Found a suitable passenger flight in { days_later } days:| * data = pass_flight->get_description( ) ). data = pass_flight->lif_output~get_output( ) ).
    2. Ajuste el código de la siguiente manera:

      ABAP
      123
      out->write( name = |Found a suitable cargo flight in { days_later2 } days:| * data = cargo_flight->get_description( ) ). data = cargo_flight->lif_output~get_output( ) ).
  4. Defina un alias para el método de interfaz LIF_OUTPUT~GET_OUTPUT para facilitar la llamada al método (nombre de alias sugerido: GET_OUTPUT).

    Consejo

    Si define el alias en la clase superior LCL_FLIGHT, lo heredan las dos subclases.
    1. Vaya a la definición de la clase local LCL_FLIGHT.

    2. Ajuste el código de la siguiente manera:

      ABAP
      1234
      CLASS lcl_flight DEFINITION ABSTRACT. PUBLIC SECTION. INTERFACES lif_output. ALIASES get_output for lif_output~get_output.
  5. Vuelva a la implementación del método IF_OO_ADT_CLASSRUN~MAIN y sustituya LIF_OUTPUT~GET_OUTPUT por el alias.

    1. Ajuste el código de la siguiente manera:

      ABAP
      1234
      out->write( name = |Found a suitable passenger flight in { days_later } days:| * data = pass_flight->get_description( ) ). * data = pass_flight->lif_output~get_output( ) ). data = pass_flight->get_output( ) ).
    2. Ajuste el código de la siguiente manera:

      ABAP
      1234
      out->write( name = |Found a suitable cargo flight in { days_later2 } days:| * data = cargo_flight->get_description( ) ). * data = cargo_flight->lif_output~get_output( ) ). data = cargo_flight->get_output( ) ).
  6. Active y pruebe su clase global como aplicación de consola.

    1. Pulse Ctrl + F3.

    2. Pulse F9.