Observa que su código, en su forma actual, permite que existan varias instancias de LCL_CARRIER, que representan a la misma compañía aérea. Para solucionarlo, definirá e implementará un método factory que garantice que solo se pueda crear una instancia para un valor de ID de transportista determinado.
Tarea 1: Copiar plantilla (opcional)
Copie la clase de modelo /LRN/CL_S4D401_OOS_INTF_USAGE. Si ha finalizado el ejercicio anterior, puede omitir esta tarea y continuar editando su clase ZCL_##_SOLUTION.
Pasos
Copie la clase /LRN/CL_S4D401_OOS_INTF_USAGE en una clase de su propio paquete (nombre sugerido: ZCL_##_SOLUTION, donde ## representa su número de grupo).
En el Explorador de proyectos, haga clic con el botón derecho en la clase /LRN/CL_S4D401_OOS_INTF_USAGE para abrir el menú contextual.
En el menú contextual, seleccione Duplicar....
Introduzca el nombre del paquete en el campo Paquete. En el campo Nombre, introduzca ZCL_##_SOLUTION, donde ## representa su número de grupo.
Seleccione Siguiente.
Confirme la orden de transporte y seleccione Finalizar.
Active la copia.
Pulse Ctrl + F3 para activar la clase.
Tarea 2: Definir un método factory
Utilice una corrección rápida para definir un método factory para la clase local LCL_CARRIER (nombre sugerido: GET_INSTANCE). En el método factory, realice la verificación de existencia y la verificación de autorización antes de crear realmente una instancia. A continuación, restrinja la creación de instancias para esta clase para forzar la utilización del método factory.
Pasos
En la clase local LCL_CARRIER, utilice una corrección rápida para definir un método factory.
Consejo
Los parámetros del constructor se añaden a la firma del método factory de forma predeterminada. Por lo tanto, no seleccione explícitamente el atributo carrier_id como atributo a inicializar.
Navegue a la definición de LCL_CARRIER.
En la sentencia CLASS … DEFINITION, sitúe el cursor en lcl_carrier y pulse Ctrl + 1 para invocar las correcciones rápidas disponibles.
De la lista de correcciones rápidas disponibles, seleccione Generar método factory crear.
En el campo Nombre, introduzca GET_INSTANCE.
En la sección Seleccionar atributos para inicializar, seleccione Desmarcar todo y, a continuación, Finalizar.
La corrección rápida debería haber añadido la siguiente definición de método:
12345
CLASS-METHODS get_instance
IMPORTING
i_carrier_id TYPE /dmo/carrier_id
RETURNING
value(r_result) TYPE REF TO lcl_carrier.
… y la siguiente aplicación:
123
METHOD get_instance.
r_result = NEW #( i_carrier_id = i_carrier_id ).
ENDMETHOD.
Mueva la sentencia SELECT y la sentencia AUTHORITY-CHECK del CONSTRUCTOR a la implementación del método factory. Asegúrese de realizar las verificaciones antes de la instanciación.
Navegue hasta la implementación del método CONSTRUCTOR de la clase local LCL_CARRIER.
Seleccione la sentencia SELECT y la sentencia AUTHORITY-CHECK, incluida la evaluación del campo de sistema SY-SUBRC y la emisión de excepciones, y pulse Ctrl + C para copiar el fragmento de código en el portapapeles.
Pulse Ctrl + < para añadir un signo de comentario delante de cada fila de código seleccionada.
Navegue a la implementación del método GET_INSTANCE, sitúe el cursor antes de la valoración para el parámetro r_result y pulse Ctrl + V para insertar el fragmento de código.
El código ahora debería tener el siguiente aspecto:
12345678910111213141516171819202122
METHOD get_instance.
SELECT SINGLE
FROM /lrn/carrier
FIELDS concat_with_space( carrier_id, name, 1 ), currency_code
WHERE carrier_id = @i_carrier_id
INTO ( @me->name, @me->currency_code ).
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.
AUTHORITY-CHECK
OBJECT '/LRN/CARR'
ID '/LRN/CARR' FIELD i_carrier_id
ID 'ACTVT' FIELD '03'.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_abap_auth_check_exception.
ENDIF.
r_result = NEW #( i_carrier_id = i_carrier_id ).
ENDMETHOD.
Dado que ha eliminado las sentencias RAISE EXCEPTION de la implementación del método CONSTRUCTOR, borre ahora los dos suplementos RAISING correspondientes en la firma de la definición del método CONSTRUCTOR.
Navegue a la definición del método CONSTRUCTOR en LCL_CARRIER.
Ajuste la definición del método de la siguiente manera:
123456
METHODS constructor
IMPORTING
i_carrier_id TYPE /dmo/carrier_id
.
Vuelva a la implementación del método GET_INSTANCE. En la sentencia SELECT, ajuste la cláusula INTO. Almacene el resultado en una estructura declarada en línea (nombre sugerido: detalles) en lugar del nombre de los atributos de instancia y currency_code.
Ajuste el código de la siguiente manera:
1234567
SELECT SINGLE
FROM /lrn/carrier
FIELDS concat_with_space( carrier_id, name, 1 ) AS name,
currency_code
WHERE carrier_id = @i_carrier_id
INTO @DATA(details).
Después de la instanciación del objeto transportista, asigne los valores de la estructura de detalles a los atributos de instancia correspondientes de la nueva instancia.
Ajuste el código de la siguiente manera:
12345
r_result = NEW #( i_carrier_id = i_carrier_id ).
r_result->name = details-name.
r_result->currency_code = details-currency_code.
ENDMETHOD.
Utilice una corrección rápida para añadir declaraciones de emisión para las dos excepciones.
Seleccione el icono de advertencia con la bombilla en la parte izquierda de la primera sentencia RAISE EXCEPTION para invocar las correcciones rápidas disponibles.
En la lista de correcciones rápidas disponibles, seleccione Agregar declaración de emisión.
Repita esto para la otra sentencia RAISE EXCEPTION.
La corrección rápida debería haber ajustado el código de la siguiente manera:
12345678
CLASS-METHODS get_instance
IMPORTING
i_carrier_id TYPE /dmo/carrier_id
RETURNING
value(r_result) TYPE REF TO lcl_carrier
RAISING
cx_abap_invalid_value
cx_abap_auth_check_exception.
Restrinja la instanciación de la clase local LCL_CARRIER. Asegúrese de que la instanciación solo está permitida dentro de la propia clase.
Navegue a la definición de LCL_CARRIER.
Ajuste el código de la siguiente manera:
1
CLASS lcl_carrier DEFINITION CREATE PRIVATE.
Mueva la definición del método CONSTRUCTOR a la sección privada.
Nota
Esto es opcional, pero debe hacerse para mejorar la legibilidad.
Copie y pegue la sentencia METHODS para el método CONSTRUCTOR de la sección pública a la sección privada.
En el método IF_OO_ADT_CLASSRUN~MAIN de la clase global, sustituya la expresión NEW por una llamada del método factory GET_INSTANCE.
Ajuste el código de la siguiente manera:
12
DATA(carrier) = lcl_carrier=>get_instance( i_carrier_id = c_carrier_id ).
En el método CLASS_SETUP de la clase de test local LTCL_FIND_FLIGHTS, sustituya la expresión NEW por una llamada del método factory GET_INSTANCE.
Ajuste el código de la siguiente manera:
12
the_carrier = lcl_carrier=>get_instance( i_carrier_id = some_flight_data-carrier_id ).
Active y pruebe su clase global como aplicación de consola. Depure la ejecución del método GET_INSTANCE.
Pulse Ctrl + F3.
Pulse F9.
Tarea 3: Ampliar el método factory
En la clase local LCL_CARRIER, defina un atributo estático en el que puede almacenar referencias a las instancias de LCL_CARRIER (nombre sugerido: instancias). A continuación, amplíe la implementación del método factory: Después de la creación de una instancia, almacene la referencia a la nueva instancia en instancias de atributo. Cree una instancia nueva solo si las instancias aún no hacen referencia a un objeto para el ID de transportista solicitado.
Pasos
En la clase local LCL_CARRIER, utilice una corrección rápida para crear un tipo de tabla para esta clase (nombre sugerido: tt_carrier).
Navegue a la definición de la clase local LC_CARRIER.
En la sentencia CLASS … DEFINITION, sitúe el cursor en lcl_carrier y pulse Ctrl + 1 para invocar las correcciones rápidas disponibles.
En la lista de correcciones rápidas disponibles, seleccione Generar tipo de tabla para lcl_carrier.
En la nueva sentencia TYPES, sustituya tab por tt_carrier.
La sentencia TYPES ahora debería tener el siguiente aspecto:
12
TYPES: tt_carriers TYPE STANDARD TABLE OF REF TO lcl_carrier
WITH DEFAULT KEY.
Defina un atributo estático privado basado en el tipo de tabla recién creado (nombre sugerido: instancias).
Desplácese hacia abajo hasta la sentencia PRIVATE SECTION.
Ajuste el código de la siguiente manera:
12
PRIVATE SECTION.
CLASS-DATA instances TYPE tt_carriers.
Ajuste la implementación del método factory GET_INSTANCE. Después de la instanciación, añada una referencia a la nueva instancia al atributo de instancias.
Ajuste el código de la siguiente manera:
123456
r_result = NEW #( i_carrier_id = i_carrier_id ).
r_result->name = details-name.
r_result->currency_code = details-currency_code.
APPEND r_result TO instances.
ENDMETHOD.
Antes de la instanciación, pero después de las verificaciones de existencia y autorización, implemente un registro individual leído de instancias de atributo. Lea la instancia en la que el valor del atributo carrier_id es igual al valor del parámetro de importación i_carrier_id. Almacene el resultado en el parámetro de retorno r_result.
Consejo
Recuerde que en las tablas internas con tipo de fila no estructurado se abordan los datos mediante el pseudocomponente table_line.
Ajuste el código de la siguiente manera:
1234567891011
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_abap_auth_check_exception.
ENDIF.
r_result = instances[ table_line->carrier_id = i_carrier_id ].
r_result = NEW #( i_carrier_id = i_carrier_id ).
r_result->name = details-name.
r_result->currency_code = details-currency_code.
APPEND r_result TO instances.
Rodea el acceso de lectura de registro individual, la instanciación, las asignaciones de valores a los atributos y la sentencia APPEND con un TRY... estructura de control ENDTRY.
Ajuste el código de la siguiente manera:
123456789
TRY.
r_result = instances[ table_line->carrier_id = i_carrier_id ].
r_result = NEW #( i_carrier_id = i_carrier_id ).
r_result->name = details-name.
r_result->currency_code = details-currency_code.
APPEND r_result TO instances.
ENDTRY.
Asegúrese de crear solo una instancia y añádala a instancias de atributo si se genera la excepción de sistema CX_SY_ITAB_LINE_NOT_FOUND.
Ajuste el código de la siguiente manera:
123456789
TRY.
r_result = instances[ table_line->carrier_id = i_carrier_id ].
CATCH cx_sy_itab_line_not_found.
r_result = NEW #( i_carrier_id = i_carrier_id ).
r_result->name = details-name.
r_result->currency_code = details-currency_code.
APPEND r_result TO instances.
ENDTRY.
En su clase global, ajuste la implementación del método IF_OO_ADT_CLASSRUN~MAIN: implemente una segunda llamada al método factory GET_INSTANCE con la misma entrada que la llamada existente, pero una variable de referencia diferente para el resultado (nombre sugerido: carrier2).
Ajuste el código de la siguiente manera:
12
DATA(carrier) = lcl_carrier=>get_instance( i_carrier_id = c_carrier_id ).
DATA(carrier2) = lcl_carrier=>get_instance( i_carrier_id = c_carrier_id ).
Active y pruebe su clase global como aplicación de consola. Depure el código para asegurarse de que las dos llamadas del método factory devuelven la misma instancia de LCL_CARRIER.
Pulse Ctrl + F3.
Pulse F9.