Vous remarquez que votre code, dans sa forme actuelle, permet à plusieurs instances de LCL_CARRIER d'exister, représentant la même compagnie aérienne. Pour résoudre ce problème, vous allez définir et implémenter une méthode Factory qui garantit qu'une seule instance peut être créée pour une valeur d'ID de transporteur donnée.
Tâche 1: Copier modèle (facultatif)
Copiez la classe de modèle /LRN/CL_S4D401_OOS_INTF_USAGE. Si vous avez terminé l'exercice précédent, vous pouvez ignorer cette tâche et continuer à modifier votre classe ZCL_##_SOLUTION.
Étapes
Copiez la classe /LRN/CL_S4D401_OOS_INTF_USAGE dans une classe de votre propre package (nom proposé : ZCL_##_SOLUTION, ## correspondant à votre numéro de groupe).
Dans l'explorateur de projet, cliquez avec le bouton droit de la souris sur la classe /LRN/CL_S4D401_OOS_INTF_USAGE pour ouvrir le menu contextuel.
Dans le menu contextuel, sélectionnez Dupliquer....
Saisissez le nom de votre package dans la zone Package. Dans la zone Nom, saisissez ZCL_##_SOLUTION, où ## représente votre numéro de groupe.
Cliquez sur Next.
Confirmez l'ordre de transport et cliquez sur Terminer.
Activez la copie.
Appuyez sur Ctrl + F3 pour activer la classe.
Tâche 2: Définir une méthode Factory
Utilisez un correctif rapide pour définir une méthode Factory pour la classe locale LCL_CARRIER (nom suggéré : GET_INSTANCE). Dans la méthode Factory, exécutez le contrôle d'existence et le contrôle des autorisations avant de créer réellement une instance. Limitez ensuite la création d'instance pour cette classe afin d'appliquer l'utilisation de la méthode Factory.
Étapes
Dans la classe locale LCL_CARRIER, utilisez un quickfix pour définir une méthode Factory.
Astuce
Les paramètres de constructeur sont ajoutés à la signature de la méthode Factory par défaut. Par conséquent, ne sélectionnez pas explicitement l'attribut carrier_id comme attribut à initialiser.
Naviguez vers la définition de LCL_CARRIER.
Dans l'instruction CLASS … DEFINITION, placez le curseur sur lcl_carrier et appuyez sur Ctrl + 1 pour appeler les solutions rapides disponibles.
Dans la liste des solutions rapides disponibles, sélectionnez Générer méthode Factory Créer.
Dans la zone Nom, saisissez GET_INSTANCE.
Dans la section Sélectionner les attributs à initialiser, sélectionnez Désélectionner tout, puis Terminer.
Le correctif rapide doit avoir ajouté la définition de méthode suivante :
12345
CLASS-METHODS get_instance
IMPORTING
i_carrier_id TYPE /dmo/carrier_id
RETURNING
value(r_result) TYPE REF TO lcl_carrier.
… et la mise en œuvre suivante :
123
METHOD get_instance.
r_result = NEW #( i_carrier_id = i_carrier_id ).
ENDMETHOD.
Déplacez l'instruction SELECT et l'instruction AUTHORITY-CHECK de CONSTRUCTOR vers l'implémentation de la méthode Factory. Assurez-vous d'effectuer les contrôles avant l'instanciation.
Naviguez vers l'implémentation de la méthode CONSTRUCTOR de la classe locale LCL_CARRIER.
Sélectionnez l'instruction SELECT et l'instruction AUTHORITY-CHECK, y compris l'évaluation de la zone système SY-SUBRC et l'exception déclenchée, puis appuyez sur Ctrl + C pour copier l'extrait de code dans le presse-papiers.
Appuyez sur Ctrl + < pour ajouter un signe de commentaire devant chaque ligne de code sélectionnée.
Naviguez jusqu'à l'implémentation de la méthode GET_INSTANCE, placez le curseur avant la valorisation pour le paramètre r_result et appuyez sur Ctrl + V pour insérer l'extrait de code.
Le code doit maintenant ressembler à ceci :
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.
Comme vous avez supprimé les instructions RAISE EXCEPTION de l'implémentation de la méthode CONSTRUCTOR, supprimez maintenant les deux ajouts RAISING correspondants dans la signature de la définition de méthode CONSTRUCTOR.
Naviguez vers la définition de la méthode CONSTRUCTOR dans LCL_CARRIER.
Adaptez la définition de méthode comme suit :
123456
METHODS constructor
IMPORTING
i_carrier_id TYPE /dmo/carrier_id
.
Revenez à l'implémentation de la méthode GET_INSTANCE. Dans l'instruction SELECT, ajustez la clause INTO. Stockez le résultat dans une structure déclarée en ligne (nom suggéré : détails) au lieu du nom des attributs d'instance et currency_code.
Adaptez le code comme suit :
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).
Après l'instanciation de l'objet porteur, affectez les valeurs de la structure détaillée aux attributs d'instance correspondants de la nouvelle instance.
Adaptez le code comme suit :
12345
r_result = NEW #( i_carrier_id = i_carrier_id ).
r_result->name = details-name.
r_result->currency_code = details-currency_code.
ENDMETHOD.
Utilisez un correctif rapide pour ajouter des déclarations pour les deux exceptions.
Cliquez sur l'icône d'avertissement avec l'ampoule à gauche de la première instruction RAISE EXCEPTION pour appeler les solutions rapides disponibles.
Dans la liste des solutions rapides disponibles, sélectionnez Ajouter déclaration de retrait.
Répétez cette opération pour l'autre instruction RAISE EXCEPTION.
Le correctif rapide doit avoir ajusté le code comme suit :
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.
Limitez l'instanciation de la classe locale LCL_CARRIER. Assurez-vous que l'instanciation est autorisée uniquement dans la classe elle-même.
Naviguez vers la définition de LCL_CARRIER.
Adaptez le code comme suit :
1
CLASS lcl_carrier DEFINITION CREATE PRIVATE.
Déplacez la définition de la méthode CONSTRUCTOR vers la section privée.
Remarque
Ceci est facultatif, mais devrait être fait pour améliorer la lisibilité.
Copiez et collez l'instruction METHODS pour la méthode CONSTRUCTOR de la section publique vers la section privée.
Dans la méthode IF_OO_ADT_CLASSRUN~MAIN de la classe globale, remplacez l'expression NEW par un appel de la méthode Factory GET_INSTANCE.
Adaptez le code comme suit :
12
DATA(carrier) = lcl_carrier=>get_instance( i_carrier_id = c_carrier_id ).
Dans la méthode CLASS_SETUP de la classe de test locale LTCL_FIND_FLIGHTS, remplacez l'expression NEW par un appel de la méthode Factory GET_INSTANCE.
Adaptez le code comme suit :
12
the_carrier = lcl_carrier=>get_instance( i_carrier_id = some_flight_data-carrier_id ).
Activez et testez votre classe globale comme application de console. Déboguez l'exécution de la méthode GET_INSTANCE.
Appuyez sur Ctrl + F3.
Appuyez sur F9.
Tâche 3: Étendre la méthode Factory
Dans la classe locale LCL_CARRIER, définissez un attribut statique dans lequel vous pouvez archiver des références aux instances de LCL_CARRIER (nom suggéré : instances). Étendez ensuite l'implémentation de la méthode Factory : après la création d'une instance, stockez la référence à la nouvelle instance dans les instances d'attributs. Créez une nouvelle instance uniquement si les instances ne font pas encore référence à un objet pour l'ID de transporteur demandé.
Étapes
Dans la classe locale LCL_CARRIER, utilisez un quickfix pour créer un type de table pour cette classe (nom suggéré : tt_porteuses).
Naviguez vers la définition de la classe locale LC_CARRIER.
Dans l'instruction CLASS … DEFINITION, placez le curseur sur lcl_carrier et appuyez sur Ctrl + 1 pour appeler les solutions rapides disponibles.
Dans la liste des solutions rapides disponibles, sélectionnez Générer type de table pour lcl_Carrier.
Dans la nouvelle instruction TYPES, remplacez l'onglet par tt_porteuses.
L'instruction TYPES doit maintenant ressembler à ceci :
12
TYPES: tt_carriers TYPE STANDARD TABLE OF REF TO lcl_carrier
WITH DEFAULT KEY.
Définissez un attribut statique privé basé sur le type de table que vous venez de créer (nom suggéré : instances).
Faites défiler vers le bas jusqu'à l'instruction SECTION PRIVÉE.
Adaptez le code comme suit :
12
PRIVATE SECTION.
CLASS-DATA instances TYPE tt_carriers.
Adaptez l'implémentation de la méthode Factory GET_INSTANCE. Après l'instanciation, ajoutez une référence à la nouvelle instance à l'attribut des instances.
Adaptez le code comme suit :
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.
Avant l'instanciation, mais après les contrôles d'existence et d'autorisation, implémentez un enregistrement individuel lu à partir des instances d'attributs. Lisez l'instance dans laquelle la valeur de l'attribut carrier_id est égale à la valeur du paramètre d'import i_carrier_id. Enregistrez le résultat dans le paramètre de retour r_result.
Astuce
N'oubliez pas que dans les tables internes avec un type de ligne non structuré, vous adressez les données à l'aide du pseudo-composant table_line.
Adaptez le code comme suit :
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.
Entourez l'accès en lecture à un enregistrement individuel, l'instanciation, les valorisations pour les attributs et l'instruction APPEND avec un TRY... ENDTRY structure de contrôle.
Adaptez le code comme suit :
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.
Assurez-vous de créer une instance et de l'ajouter uniquement aux instances d'attributs si l'exception système CX_SY_ITAB_LINE_NOT_FOUND est déclenchée.
Adaptez le code comme suit :
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.
Dans votre classe globale, ajustez l'implémentation de la méthode IF_OO_ADT_CLASSRUN~MAIN : implémentez un deuxième appel de la méthode Factory GET_INSTANCE avec la même entrée que l'appel existant, mais une variable de référence différente pour le résultat (nom proposé : carrier2).
Adaptez le code comme suit :
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 ).
Activez et testez votre classe globale comme application de console. Déboguez le code pour vous assurer que les deux appels de la méthode Factory retournent la même instance de LCL_CARRIER.
Appuyez sur Ctrl + F3.
Appuyez sur F9.