コードの分析およびテスト
データ型およびデータ型変換の正しい使用
文字項目の処理
ABAP SQL でのコードプッシュダウンの使用
内部テーブルのパフォーマンスの改善
権限チェックの実装
効果的なオブジェクト指向コードの設計
例外クラスの定義と処理
ABAP コードへの文書の追加

インタフェースの使用

Objective

After completing this lesson, you will be able to インタフェースの使用

インタフェース使用

インタフェース参照の宣言

参照変数を宣言するための参照タイプとしてインタフェースを使用することができます。以前に学習したとおり、クラスのインスタンスを生成/管理するには、参照変数を使用します。インタフェースはインスタンス化できないため、インタフェース参照を使用して、どのようなタイプのオブジェクトを管理できるのかについて疑問に思うかもしれません。

インタフェース参照には、スーパークラスのデータ型を持つ参照変数に任意のサブクラスのインスタンスへの参照を含めることができるのと同様に、インタフェースを実装するクラスのインスタンスへの参照を含めることができます。(スーパークラスが抽象的であると想定すると、スーパークラスに関連する他のクラスのインスタンスへの参照をインスタンス化できないデータ型と同じ状況になります)。

スーパークラスの 1 つのサブクラスのインスタンスを管理するためにスーパークラス型の変数を使用するときには、スーパークラスで定義されたコンポーネントのみにアクセスすることができます。同様に、インタフェースを実装するクラスのインスタンスを管理するためにインタフェース参照を使用するときには、インタフェースで定義されたコンポーネントのみにアクセスすることができます。つまり、クラスの特定のフレームワークの開発者は、クラスが実行できるすべての単一処理を公開するのではなく、クラスの特定のビューを提供するインタフェースを出荷することができます。

クラス型の参照変数を使用して、インタフェースからメソッドを呼び出すことができます。この場合、メソッドの完全修飾名 (インタフェース名を含む) を使用する必要があります。メソッドのエイリアスを定義している場合は、それを使用することができます。インタフェース参照を使用してインタフェースメソッドを呼び出すときには、インタフェース名が参照変数の型から推測されるため、メソッド名の前にインタフェース名を指定する必要がありません。

インタフェース参照によるキャスト

オブジェクト参照をインタフェース参照に割り当てることは "キャスト" とも呼ばれます。たとえば、航空会社 (carrier) オブジェクトやレンタカー会社 (rental) オブジェクトを取引先であるかのようにみなします。実装クラスのインスタンスを常にインタフェース参照に割り当てることができます。これは "アップキャスト" と呼ばれ、クラスがインタフェースを実装するという事実によって裏付けされます。ただし、構文チェックでは、実際の実行時オブジェクトに互換性があるかどうかを判別できないため、インタフェース参照から実装クラス型の参照にオブジェクトを割り当てることはできません。割当 rental = partner は、インタフェース参照のオブジェクトが実際に lcl_car_rental のインスタンスである場合に機能しますが、別の実装クラスのインスタンスである場合は、実行時エラーが発生します。

継承の場合と同じ方法で "ダウンキャスト" を実行できます。ここでの解決方法は同じです。インタフェース型の参照変数からクラスのタイプのオブジェクト参照にオブジェクト参照を割り当てる必要がある場合は (クラスの特定の機能にアクセスできるように)、CAST 演算子を使用する必要があります。このケースの正しい解決法は次のようになります。

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

試してみる: インタフェース使用

  1. インタフェース IF_OO_ADT_CLASSRUN を実装する新しいクラスを登録します。
  2. Local Types タブに切り替えて、以下のコードスニペットをエディタにコピーします。
    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. Global Class タブに切り替えて、以下のコードスニペットをメソッド 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.

インタフェースメソッドの呼出

前の演習問題では、インタフェース LIF_OUTPUT を定義し、クラス LCL_CARRIER および LCL_FLIGHT に実装しました。グローバルクラスで、作成した Carrier インスタンスに対して LIF_OUTPUT インタフェースからの get_output メソッドがすでに呼び出されています。この演習問題では、クラス LCL_PASSENGER_FLIGHT および LCL_CARGO_FLIGHT のインスタンスの get_output インタフェースメソッドも呼び出します。

テンプレート:

  • /LRN/CL_S4D401_OOS_INTERFACE (グローバルクラス)

ソリューション:

  • /LRN/CL_S4D401_OOS_INTF_USAGE (グローバルクラス)

タスク 1: テンプレートのコピー (オプション)

テンプレートクラス /LRN/CL_S4D401_OOS_INTERFACE をコピーします。前の演習問題を完了した場合は、このタスクをスキップし、クラス ZCL_##_SOLUTION の編集を続行することができます。

ステップ

  1. クラス /LRN/CL_S4D401_OOS_INTERFACE を各自のパッケージのクラスにコピーします (推奨名: ZCL_##_SOLUTION、## はグループ番号)。

    1. Project Explorer で、クラス /LRN/CL_S4D401_OOS_INTERFACE を右クリックしてコンテキストメニューを開きます。

    2. コンテキストメニューから Duplicate.... を選択します。

    3. Package 項目にパッケージの名称を入力します。Name 項目に、ZCL_##_SOLUTION (## はグループ番号) と入力します。

    4. Next を選択します。

    5. 移送依頼を確認し、Finish を選択します。

  2. コピーを有効化します。

    1. Ctrl + F3 を押してクラスを有効化します。

タスク 2: インタフェースの使用

ローカルクラス LCL_FLIGHT で、インスタンスメソッド GET_DESCRIPTION の可視性を変更し、代わりに外部ユーザにメソッド GET_OUTPUT の呼出を強制します。次に、メソッド IF_OO_ADT_CLASSRUN~MAIN の実装を適宜調整します。

ステップ

  1. ローカルクラス LCL_FLIGHT で、クイックフィックスを使用して、インスタンスメソッド GET_DESCRIPTION の可視性を保護済に変更します。

    1. ローカルクラス LCL_FLIGHT のメソッド GET_DESCRIPTION の定義にナビゲートします。

    2. METHODS 命令で、get_description にカーソルを置き、Ctrl + 1 を押して利用可能なクイックフィックスを呼び出します。

    3. 利用可能なクイックフィックスの一覧から Make get_description protected を選択します。

  2. サブクラス LCL_PASSENGER_FLIGHT および LCL_CARGO_FLIGHTGET_DESCRIPTION の再定義の可視性を変更します。

    注記

    再定義をマニュアルでコピーする必要があります。再定義の可視性を変更するためのクイックフィックスはまだありません。
    1. ローカルクラス LCL_PASSENGER_FLIGHT のメソッド GET_DESCRIPTION の再定義にナビゲートします。

    2. METHODS 命令を選択し、Ctrl + X を押します。

    3. PROTECTED SECTION 命令の後の次の行にカーソルを置き、Ctrl + V を押します。

    4. ローカルクラス LCL_CARGO_FLGHT でこれを繰り返します。

  3. メソッド GET_DESCRIPTION が呼び出されるメソッド IF_OO_ADT_CLASSRUN~MAIN の実装を調整します。メソッド GET_DESCRIPTION をインタフェースメソッド GET_OUTPUT に置き換えます。

    ヒント

    Problems ビューの 2 つのエラーメッセージを使用して、メソッド GET_DESCRIPTION が呼び出されている場所にナビゲートします。
    1. コードを以下のように調整します。

      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. コードを以下のように調整します。

      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. インタフェースメソッド LIF_OUTPUT~GET_OUTPUT のエイリアスを定義して、メソッドをより簡単に呼び出せるようにします (推奨エイリアス名: GET_OUTPUT)。

    ヒント

    スーパークラス LCL_FLIGHT でエイリアスを定義すると、そのエイリアスは 2 つのサブクラスに継承されます。
    1. ローカルクラス LCL_FLIGHT の定義にナビゲートします。

    2. コードを以下のように調整します。

      ABAP
      1234
      CLASS lcl_flight DEFINITION ABSTRACT. PUBLIC SECTION. INTERFACES lif_output. ALIASES get_output for lif_output~get_output.
  5. メソッド IF_OO_ADT_CLASSRUN~MAIN の実装に戻り、LIF_OUTPUT~GET_OUTPUT をエイリアスに置き換えます。

    1. コードを以下のように調整します。

      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. コードを以下のように調整します。

      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. グローバルクラスをコンソールアプリとして有効化してテストします。

    1. Ctrl + F3 を押します。

    2. F9 を押します。