Introduction
Application des techniques et concepts de base
Utilisation des classes locales
Lecture des données de la base de données
Utilisation d'objets de données structurés
Utilisation de tables internes complexes
Implémentation de mises à jour de base de données à l'aide d'objets de gestion
Description du modèle de programmation d'applications ABAP RESTful

Utilisation de l'encapsulation pour garantir la cohérence

Objectives

After completing this lesson, you will be able to:
  • Expliquez l'encapsulation.
  • Définissez et utilisez des constructeurs.

Encapsulation des données

Dans la programmation orientée objet, un objet correspond à un objet de la vie réelle tel qu'un employé, un véhicule ou, dans notre cas, une liaison aérienne. Il a des attributs qui le décrivent, dans le cas d'une liaison aérienne, il s'agit de l'ID du transporteur et du numéro de vol.

Réfléchissons maintenant à ce qui se passe lorsqu'un programme qui utilise cet objet veut fournir des valeurs pour ces attributs. Il est évident que seules les combinaisons d'ID de transporteur et de numéro de vol correspondant à une liaison aérienne dans le monde réel devraient être acceptées.

Dans l'orientation objet, le programme client ne doit pas pouvoir modifier directement les valeurs d'attribut. Au lieu de cela, il doit appeler une méthode pour effectuer cette tâche. La méthode fournie avec l'objet peut alors vérifier si la combinaison de l'ID du transporteur et du numéro de vol est valide et, si ce n'est pas le cas, rejeter la modification.

En tant que développeurs de la classe lcl_connection, nous pouvons garantir l'utilisation de la méthode set_attributes( ) en rendant les attributs carrier_id et connection_id privés, ou du moins en lecture seule.

Ce concept est appelé encapsulation de données ; les informations sur la liaison aérienne sont gérées par l'objet de raccordement lui-même et ne peuvent pas être manipulées par quelqu'un d'autre. Cela garantit que le contrôle de cohérence ne peut pas être contourné, que ce soit en connaissance de cause ou sans le savoir. C'est l'un des principaux avantages de l'orientation objet.

Dans la programmation orientée objet, il est recommandé d'utiliser l'encapsulation de données autant que possible !

Avec les attributs publics que nous avons définis maintenant, il était possible de lire et de modifier les valeurs des attributs n'importe où à l'intérieur et à l'extérieur de la classe.

Pour limiter l'accès aux attributs, vous disposez de deux options :

  1. Conservez l'instruction DATA ou l'instruction CLASS-DATA dans la section publique et ajoutez l'option READ-ONLY. Ce faisant, l'accès en écriture à l'attribut est interdit en dehors de la classe, mais l'accès en lecture est toujours possible.

    Remarque

    L’ajout de READ-ONLY n’est autorisé que dans la section publique d’une session.
  2. Déplacez l'instruction DATA ou CLASS-DATA de la section publique vers l'une des autres sections de visibilité, par exemple la section privée. Ce faisant, l'accès en lecture et en écriture à l'attribut est interdit en dehors de la classe.

    Astuce

    ADT offre un correctif rapide pour modifier la visibilité d'un attribut. Pour l'utiliser, placez le curseur dans le nom de l'attribut, appuyez sur Ctrl + 1 et sélectionnez Rendre <attribut> privé.

Comment utiliser des attributs privés

Constructeur d'instance

En rendant vos attributs privés - ou en lecture seule, au moins - vous pouvez vous assurer que le programme client utilise la méthode set_attributes( ) disponible pour définir les valeurs des attributs carrier_id et connection_id.

Cependant, il existe encore un risque d'incohérences :

  • Vous ne pouvez pas forcer le programme à appeler set_attributes( ) pour chaque nouvelle instance. Par conséquent, il peut y avoir des instances avec des valeurs initiales pour carrier_id et connection_id.
  • Le programme client peut appeler set_attributes( ) plusieurs fois pour la même instance. Cela ne devrait pas non plus être possible.

Vous avez besoin d'une technique permettant d'appliquer des valeurs non initiales lors de l'instanciation et d'empêcher les modifications ultérieures.

Pour résoudre ces problèmes, les langages de programmation orientés objet utilisent des méthodes constructrices.

Le système d'exécution appelle automatiquement le constructeur lorsque vous créez une nouvelle instance de la classe, mais vous ne pouvez pas l'appeler explicitement. Ainsi, l'exécution du constructeur est garantie une et une seule fois pour chaque instance que vous créez.

Du point de vue de la syntaxe, une méthode constructeur possède les propriétés suivantes :

  • une méthode d'instance publique avec le constructeur de nom réservé
  • peut avoir des paramètres d'importation, par exemple pour obtenir des valeurs de départ pour les attributs de la nouvelle instance
  • peut générer des exceptions

Remarque

En ABAP, il n'est pas possible de définir plusieurs méthodes de constructeur dans la même classe.

Astuce

Dans ADT, vous pouvez utiliser un correctif rapide pour générer une méthode de constructeur. Pour utiliser ce correctif rapide, procédez comme suit :

  1. Dans la partie définition ou dans la partie implémentation, placez le curseur dans le nom de classe et appuyez sur Ctrl + 1.
  2. Dans la liste des solutions rapides disponibles, sélectionnez Générer constructeur.
  3. Dans la boîte de dialogue qui s'affiche, sélectionnez les attributs que vous souhaitez initialiser avec le constructeur et cliquez sur Terminer.

Une fois que vous avez généré le constructeur, vous pouvez adapter sa définition et son implémentation à vos besoins.

L'exemple montre le constructeur de la classe lcl_connection. La définition générée contient un paramètre d'import pour chacun des attributs carrier_id et connection_id.

La partie générée de l'implémentation contient une valorisation pour chacun des attributs avec le paramètre d'importation correspondant à droite.

L'exemple montre des ajouts manuels au constructeur généré de la classe lcl_connection.

Afin de refuser la création d'instances avec des valeurs initiales, un contrôle de cohérence a été ajouté à l'implémentation et une clause RAISING a été ajoutée à la définition du constructeur.

Comme le constructeur est exécuté une seule fois pour chaque nouvelle instance de la classe lcl_connection, l'implémentation du constructeur est l'emplacement idéal pour incrémenter l'attribut statique conn_counter.

Lorsque vous instanciez une classe qui a un constructeur, le système appelle automatiquement la méthode du constructeur. Si le constructeur a des paramètres d'import, vous les transférez dans l'expression NEW exactement comme vous le feriez pour transmettre les paramètres à une méthode normale.

Remarque

Un constructeur ne peut avoir que des paramètres d'importation. Le mot-clé EXPORTING n'est ni nécessaire ni autorisé dans l'expression NEW.
Si le constructeur comporte des exceptions, vous devez vous assurer de les intercepter en insérant l'instanciation dans un bloc TRY… CATCH...ENDTRY. Si un constructeur déclenche une exception, le contrôle retourne immédiatement au programme contenant l'expression NEW. Dans ce cas, vous ne recevez pas de nouvelle instance de la classe.

Comment définir un constructeur d'instances

Constructeur statique

Alors que le constructeur d'instance est appelé une fois lorsque chaque instance d'une classe est créée, vous devrez parfois effectuer des actions une seule fois pour l'ensemble de la classe. À cette fin, ABAP vous permet de définir un constructeur statique, également appelé constructeur de classe.

Le système d'exécution n'appelle le constructeur statique qu'une seule fois lorsque la classe est adressée pour la première fois lors de l'exécution d'un programme.

Le premier adressage d'une classe peut être l'un des suivants :

  • Première instanciation de la classe
  • Premier appel d'une méthode statique
  • Premier accès à un attribut statique public

Remarque

Cette liste n'est pas complète. Il existe d'autres actions (liées à l'héritage) qui peuvent entraîner l'adressage d'une classe pour la première fois.

Un cas d'utilisation type pour le constructeur statique est l'initialisation dynamique d'attributs statiques avec des valeurs non initiales. Par conséquent, il est important que l'exécution appelle le constructeur statique avant de créer l'instance, d'appeler la méthode statique ou d'adresser l'attribut statique.

Du point de vue de la syntaxe, une méthode constructeur possède les propriétés suivantes :

  • Une méthode statique publique avec le nom réservé class_constructor
  • Sans paramètres ni exceptions

Remarque

Un constructeur statique ne doit pas avoir de signature car il est impossible de savoir exactement quand une classe sera adressée pour la première fois.

Astuce

Dans ADT, vous pouvez utiliser un correctif rapide pour générer une méthode de constructeur de classe. Pour utiliser ce correctif rapide, procédez comme suit :

  1. Dans la partie définition ou dans la partie implémentation, placez le curseur dans le nom de classe et appuyez sur Ctrl + 1.
  2. Dans la liste des solutions rapides disponibles, sélectionnez Générer constructeur de classe.

Comment déboguer l'exécution de constructeurs

Utilisation d'attributs privés et d'un constructeur

Dans cet exercice, vous rendez l'attribut statique de votre classe en lecture seule et les attributs d'instance privés. Vous utilisez un constructeur pour définir leurs valeurs.

Modèle :

  • /LRN/CL_S4D400_CLS_METHODS (classe globale)

Solution :

  • /LRN/CL_S4D400_CLS_CONSTRUCTOR (classe globale)

Tâche 1: Copier modèle (facultatif)

Copiez la classe de modèle. Si vous avez terminé l'exercice précédent, vous pouvez ignorer cette tâche et continuer à modifier votre classe (ZCL_##_METHODS, ZCL_##_LOCAL_CLASS ou ZCL_##_INSTANCES).

Étapes

  1. Copiez la classe /LRN/CL_S4D400_CLS_METHODS dans une classe de votre propre package (nom proposé : ZCL_##_CONSTRUCTOR, où ## correspond à votre numéro de groupe).

    1. Ouvrez le code source de la classe globale /LRN/CL_S4D400_CLS_METHODS.

    2. Liez la vue Explorateur de projets à l'aide de l'éditeur.

    3. Dans la vue Explorateur de projets, cliquez avec le bouton droit de la souris sur la classe /LRN/CL_S4D400_CLS_METHODS pour ouvrir le menu contextuel.

    4. Dans le menu contextuel, sélectionnez Dupliquer ....

    5. Saisissez le nom de votre package dans la zone Package. Dans la zone Nom, saisissez le nom ZCL_##_CONSTRUCTOR, où ## représente votre numéro de groupe.

    6. Ajustez la description et cliquez sur Suivant.

    7. Confirmez l'ordre de transport et cliquez sur Terminer.

Tâche 2: Rendre les attributs privés

Modifiez la visibilité des attributs carrier_id et connection_id pour forcer l'utilisation des méthodes set_attributes( ) et get_output( ).

Étapes

  1. Définissez la visibilité de l'attribut carrier_id sur Privé à l'aide d'un correctif rapide.

    1. Passez à l'onglet Types locaux.

    2. Accédez à la déclaration de l'attribut carrier_id dans la classe locale lcl_connection.

    3. Positionnez le curseur sur carrier_id et appuyez sur Ctrl + 1.

    4. Double-cliquez sur la proposition Make carrier_id private.

    5. Vérifiez que la déclaration de l'attribut carrier_id a été déplacée vers la section privée.

  2. Définissez la visibilité de l'attribut connection_id sur Privé à l'aide d'un correctif rapide.

    1. Accédez à la déclaration de l'attribut connection_id dans la classe locale lcl_connection.

    2. Placez le curseur sur connection_id et appuyez sur Ctrl + 1.

    3. Double-cliquez sur la suggestion Rendre connection_id privé.

    4. Vérifiez que la déclaration de l'attribut connection_id a été déplacée vers la section privée.

Tâche 3: Créer un constructeur d'instance

Remplacez la méthode publique set_attributes par un constructeur d'instance pour vous assurer que les attributs sont définis lors de la création d'une nouvelle instance et qu'ils ne sont pas modifiés par la suite.

Étapes

  1. Commentez la définition et l'implémentation de la méthode set_Attributes.

    1. Sélectionnez toutes les lignes qui appartiennent à l'instruction METHODS set_attributes, y compris la ligne avec le signe de période (.).

    2. Appuyez sur Ctrl + < pour ajouter un signe étoile (*) devant chaque ligne sélectionnée.

    3. Sélectionnez toutes les lignes qui appartiennent à l'implémentation de la méthode set_attributes, y compris l'instruction ENDMETHOD. correspondante, puis appuyez à nouveau sur Ctrl + <.

  2. Ajoutez un constructeur d'instance à la classe locale lcl_connection à l'aide d'un correctif rapide. Assurez-vous que le constructeur a des paramètres d'importation correspondant aux attributs carrier_id et connection_id.

    1. Positionnez le curseur sur le nom de la classe et appuyez sur Ctrl + 1.

    2. Double-cliquez sur Générer constructeur.

    3. Dans la boîte de dialogue, assurez-vous que carrier_id et connection_id sont sélectionnés, puis cliquez sur Terminer.

  3. Étendez la définition du constructeur généré. Ajoutez l'exception CX_ABAP_INVALID_VALUE à la définition du constructeur de méthode.

    1. Naviguez vers la définition générée du constructeur de méthode.

    2. Adaptez le code comme suit :

      Code Snippet
      12345678
      METHODS constructor IMPORTING i_connection_id TYPE /dmo/connection_id i_carrier_id TYPE /dmo/carrier_id RAISING cx_ABAP_INVALID_VALUE.
  4. Étendez l'implémentation du constructeur généré. Si l'un des paramètres d'importation est initial, déclenchez l'exception CX_ABAP_INVALID_VALUE.

    1. Naviguez de la définition à l'implémentation du constructeur de méthode, par exemple en positionnant le curseur sur le constructeur et en appuyant sur F3.

    2. Adaptez le code comme suit :

      Code Snippet
      123456789101112
      METHOD constructor. IF i_carrier_id IS INITIAL OR i_connection_id IS INITIAL. RAISE EXCEPTION TYPE cx_abap_invalid_value. ENDIF. me->connection_id = i_connection_id. me->carrier_id = i_carrier_id. ENDMETHOD.
  5. Dans l'implémentation du constructeur, ajoutez une instruction pour augmenter la valeur de l'attribut statique conn_counter de un. Assurez-vous que l'instruction est exécutée uniquement si aucune exception n'a été déclenchée.

    1. Adaptez le code comme suit :

      Code Snippet
      12345678
      me->connection_id = i_connection_id. me->carrier_id = i_carrier_id. conn_counter = conn_counter + 1. ENDMETHOD.
  6. Assurez-vous qu'il n'est pas possible de modifier la valeur de conn_counter en dehors de la classe.

    1. Ajoutez READ-ONLY à la déclaration de l'attribut statique conn_counter.

    2. Adaptez le code comme suit :

      Code Snippet
      123
      CLASS-DATA conn_counter TYPE i READ-ONLY.

Tâche 4: Utiliser le constructeur

Adaptez l'instanciation de la classe lcl_connection pour fournir les paramètres du constructeur d'instance et gérer l'exception.

Étapes

  1. Dans la méthode if_oo_adt_classrun~main, accédez à l'expression NEW #( ) pour la première instance de lcl_connection.

    1. Passez à l'onglet Classe globale.

    2. Recherchez la première ligne avec connection = NEW #( )..

  2. Dans l'expression NEW, indiquez les paramètres d'import du constructeur.

    Astuce

    Vous pouvez copier le paramètre transmis à partir de l'appel de la méthode set_attributes pour cette instance.
    1. Ajustez l'expression NEW comme suit :

      Code Snippet
      123456
      connection = NEW #( i_carrier_id = 'LH' i_connection_id = '0400' ).
  3. Supprimez ou commentez tous les appels de la méthode set_attributes.

    1. Sélectionnez toutes les lignes qui appartiennent à l'instruction connection->set_attributes( ... )., y compris la ligne avec la parenthèse fermante et le signe point (.).

    2. Appuyez sur Ctrl + < pour ajouter un signe étoile (*) devant chaque ligne sélectionnée.

  4. Déplacez la création d'instance dans le bloc TRY de la gestion des exceptions.

    1. Déplacez l'instruction TRY. vers le haut, avant la création de l'instance.

    2. Votre création de la première instance doit maintenant ressembler à ceci :

      Code Snippet
      12345678910111213141516171819
      TRY. connection = NEW #( i_carrier_id = 'LH' i_connection_id = '0400' ). * connection->set_attributes( * EXPORTING * i_carrier_id = 'LH' * i_connection_id = '0400' * ). APPEND connection TO connections. CATCH cx_abap_invalid_value. out->write( `Method call failed` ). ENDTRY.
  5. Répétez les étapes précédentes pour les autres instances de votre classe locale.

    1. Après cette étape, l'implémentation de la méthode if_oo_adt_classrun~main doit ressembler à ceci :

      Code Snippet
      1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
      METHOD if_oo_adt_classrun~main. DATA connection TYPE REF TO lcl_connection. DATA connections TYPE TABLE OF REF TO lcl_connection. * First Instance ********************************************************************** TRY. connection = NEW #( i_carrier_id = 'LH' i_connection_id = '0400' ). * connection->set_attributes( * EXPORTING * i_carrier_id = 'LH' * i_connection_id = '0400' * ). APPEND connection TO connections. CATCH cx_abap_invalid_value. out->write( `Method call failed` ). ENDTRY. * Second instance ********************************************************************** TRY. connection = NEW #( i_carrier_id = 'AA' i_connection_id = '0017' ). APPEND connection TO connections. CATCH cx_abap_invalid_value. out->write( `Method call failed` ). ENDTRY. * Third instance ********************************************************************** TRY. connection = NEW #( i_carrier_id = 'SQ' i_connection_id = '0001' ). APPEND connection TO connections. CATCH cx_abap_invalid_value. out->write( `Method call failed` ). ENDTRY. * Output ********************************************************************** LOOP AT connections INTO connection. out->write( connection->get_output( ) ). ENDLOOP. ENDMETHOD.
  6. Activez la classe. Exécutez-la et déboguez l'instanciation.

    1. Appuyez sur Ctrl + F3 pour activer la classe.

    2. Appuyez sur F9 pour exécuter la classe.