効果的なオブジェクト指向コードの設計

継承の実装

Objective

After completing this lesson, you will be able to 特殊なクラスを実装します。

継承の実装

一般的なクラスやより専門的なクラスのコンセプトを理解するには、このビデオを視聴してください。

継承 - "A" 関係

モデリングでは、特化について説明しました。プログラミング言語でこの関係を実装するとき、継承の概念が使用されます。継承では新しいクラス (サブクラス) が既存のクラス (スーパークラス) から派生します。2 つのクラス間に真の継承関係があるかどうかを確認するための信頼できるテストは、"サブクラスはスーパークラス" と言おうとすることです。これが明らかに真である場合、継承関係があります。明らかに真でないか、ちょっと奇妙に聞こえる場合は、継承関係を持たず、それを実装すべきではありません。そうすると、さらに下位の問題が発生する可能性があるためです。模型を試す際、「貨物機は飛行機」「旅客機は飛行機」と断言できる。

スーパークラスから継承するクラスには、スーパークラスのすべてのコンポーネントが自動的に含まれます。そのため、たとえば、旅客機クラスには、航空機と同様に製造業者とタイプがあります。旅客機は飛行機であるため、これは驚くべきではありません。最初にサプリングに見える可能性があるのは、旅客機クラスが独自のメーカーやタイプにアクセスできないことだ。これはスーパークラスのプライベート属性であるためであり、その理由から、サブクラスからはアクセスできません。サブクラスを完全にパブリックにすることなくスーパークラスのコンポーネントにアクセスできるようにする方法を、後に学習します。

継承関係の定義

ABAP では、クラス定義命令で INHERITING FROM オプションを使用して継承を実装します。この例では、旅客機クラスは航空機クラスのサブクラスとして定義されています。サブクラスはそのスーパークラスを認識していますが、航空機クラスにはサブクラスがあるかどうか (存在する場合) がわからないことに注意してください。

サブクラスには、直接のスーパークラスが 1 つしか存在しません。

1 つのスーパークラス - 任意の数のサブクラス

航空機クラスには任意の数のサブクラスがある場合がありますが、どのサブクラスも認識されません。

各サブクラスには直接のスーパークラスが 1 つずつあります。スーパークラスは把握していますが、兄弟クラス (同じスーパークラスから派生した他のクラス) はどれも把握していません。この例では、旅客機クラスに貨物機クラスに関する知識がありません。

サブクラスの拡張方法

サブクラスを宣言したら、そのサブクラスに新しいコンポーネントを追加するか、既存のコンポーネントを変更する必要があります。これは、単なる飛行機クラスのコピーを旅客機または貨物機に変えるものである。継承により、クラスを最初から実装する必要はありません。必要な新しいコンポーネントによってクラスを拡張するだけです。

以下の 3 つの方法を使用することができます。

新しいコンポーネントの追加: クラスで新しい属性、型、定数、およびメソッドを宣言できます。スーパークラスのコンポーネントの宣言にすでに使用されている他の名称と衝突しないようにする必要があります。また、新しいコンポーネントがスーパークラスの特化されたすべてのクラスではなく、サブクラスにのみ関連するようにしてください。汎用的に関連する新しい属性またはメソッドを宣言する場合は、それをスーパークラスに移動させる必要があります。

メソッドの再定義: 継承されたメソッドを呼び出すと、実行システムによってスーパークラスからメソッドの実装が実行されます。ただし、この実装ではサブクラスで宣言した新しいコンポーネントが考慮されません。この場合、メソッドを再定義することができます。つまり、サブクラスに関連する新規実装をメソッドに割り当てることができます。

新しいコンストラクタを追加します。コンストラクタによって、クラスの新しいインスタンスが正しく初期化されます。サブクラスのインスタンスを登録すると、実行システムでは常にスーパークラスのコンストラクタが実行されます。これにより、たとえば、旅客機には他の航空機とまったく同じ方法で製造業者とタイプが含まれるようになります。ただし、スーパークラスのコンストラクタはサブクラスが存在することを認識しないため、サブクラスの属性を初期化できません。このため、サブクラスに対する新しいコンストラクタを定義することができます。

新規コンポーネントの宣言

新しいコンポーネントを宣言することにより、サブクラスを拡張できます。これらは、クラス自体には表示されますが、スーパークラスには表示されず、同じスーパークラスから継承される他のクラスにも表示されません。したがって、新しいコンポーネントを現在のクラスのみに関連付けるか、スーパークラスに宣言する必要があるかを考慮する必要があります。

プロテクトコンポーネント

サブクラスにはスーパークラスの属性がすべて含まれていますが、サブクラス自体がプライベートコンポーネントに直接アクセスすることはできません。スーパークラスの特定の属性またはメソッドを完全にパブリックにすることなく、サブクラスからアクセスできるようにする必要がある場合があります。これは、保護されたセクションで宣言することで実現できます。プロテクトコンポーネントはクラス自体の中だけでなく、すべてのサブクラスから可視です。

クラス定義で、PROTECTED SECTION 命令を使用して、プロテクトセクションを導入します。可視性セクションは常に PUBLIC SECTION - PROTECTED SECTION - PRIVATE SECTION の順で宣言する必要があります。

クイックフィックスを使用して、クラスの既存のコンポーネントを移動することができます。これを行うには、ADT のコンポーネント名にカーソルを合わせ、Ctrl + 1 を押してから、クイックフィックス Make <element> protected を選択します。

保護されたセクションへのプライベートコンポーネントの移動は、互換性のある変更です。コンポーネントの可視性が拡大されました。しかし、パブリックコンポーネントをプロテクトすることは互換性のない変更であり、構文エラーが発生する可能性があります。その理由は、すでに継承階層の外で使用されている可能性があるコンポーネントの可視性を制限したためです。

メソッドの再定義

スーパークラスにサブクラス内で使用したいメソッドが含まれていることがよくありますが、サブクラスの特定の性質が考慮されていないため、メソッドの実装が不適切です。たとえば、航空機クラスの get_attributes メソッドは、旅客機クラスで定義された属性を返すことができません。ただし、旅客機クラスには引き続きメソッド get_attributes が必要です。

ABAP では、インスタンスメソッド get_attributes を再定義することで、この問題を解決することができます。メソッドを再定義する場合、サブクラスのみが把握していることを考慮に入れた新しい実装をサブクラス内に記述します。ただし、メソッドの定義はまったく同じままです。以下のルールに従う必要があります。

  • メソッドは同じ名称を維持します。
  • REDEFINITION オプションを使用して、サブクラスで宣言し、メソッドを再定義することを示します。
  • メソッドの可視性はスーパークラスもあるときと同じになります。
  • メソッドの署名は変更できません。

静的メソッドは再定義できません。

再定義の実装

メソッドの再定義を実装すると、実装をスーパークラスで呼び出すことができます。これを行うには、現在のインスタンス内のスーパークラスを指す暗黙的なオブジェクト参照 super を使用します。このようにして、スーパークラスからのメソッド実装を再利用し、それを独自の実装に追加することができます。

参照変数 super を宣言する必要はありません。それは再定義したメソッドの実装内で自動的に使用可能になります。

このようにスーパークラスでメソッドを呼び出す方法はオプションです。これが良い考えである場合もありますが、利点が何も得られない場合もあります。

新規コンストラクタ定義

サブクラスでは、新しいコンストラクタを定義することができます。メソッドの再定義とは異なり、コンストラクタには独自の署名がある場合があります。コンストラクタの署名には、スーパークラスのコンストラクタと同じパラメータに加え、独自の新しいパラメータが含まれることがあります。これは、新しいインスタンスコンストラクタに 2 つのタスクがあるためです。最初にスーパークラスのコンストラクタを呼び出し、次にサブクラスに固有の独自の属性の初期化を処理します。

新しいコンストラクタを定義するのに加えて、サブクラス内に新しい静的コンストラクタを定義することもできます。

コンストラクタのロール

サブクラスのコンストラクタには 2 つの機能があります。スーパークラスのコンポーネントが適切に初期化されていることを確認する必要があり、その後、サブクラス属性の初期値を設定することができます。

この例では、旅客機は航空機であるため、航空機クラスのコンストラクタが正常に動作して新しい旅客機の製造業者とタイプを設定しない限り、旅客機インスタンスは存在しません。この後にのみ、旅客機クラスで独自の属性を設定することができます。

したがって、サブクラスのコンストラクタは独自の属性を設定できるだけでなく、必要な値をスーパークラスのコンストラクタに渡すことも可能である必要があります。そのため、サブクラスのコンストラクタの署名には多くの場合、呼び出す必要があるコンストラクタの全署名が含まれています。

新規コンストラクタ実装の順序

新しいコンストラクタの実装では、特定の操作順序に従う必要があります。最も重要なイベントは、スーパークラスのコンストラクタを呼び出すことです。この処理は必須であり、再定義されたメソッドの元の実装を呼び出すときと同様に、暗黙的な参照の super を使用してメソッドを呼び出します。再度、super を明示的に宣言する必要はありません。

スーパークラスのコンストラクタを呼び出す前に、構築中のインスタンスのインスタンスコンポーネントをアドレスすることはできません。クラスの静的コンポーネントをアドレスし、コンストラクタのインポートパラメータが正しいことをチェックできます。正しくない場合は、例外を発生させます。

スーパークラスのコンストラクタが正常に実行されたら、新しいインスタンスのインスタンスコンポーネントをアドレスすることができます。

コンストラクタ呼出の順序

この図は静的コンストラクタおよびインスタンスコンストラクタの呼出順序を示します。この例では、プログラムが旅客機クラスをインスタンス化する必要があり、その航空機クラスが以前にアドレス指定されていないことを前提としています。

プログラムが旅客機クラスのインスタンスを登録しようとすると、実行システムによって自動的に静的コンストラクタが継承階層の最上部から順次呼び出されます。静的コンストラクタがすべて実行されると、実行システムはサブクラスのインスタンスコンストラクタを呼び出し、次にそれがスーパークラスのインスタンスコンストラクタを呼び出します。

試行: 継承実装

  1. インタフェース IF_OO_ADT_CLASSRUN を実装する新しいクラスを登録します。
  2. Local Types タブに切り替えて、以下のコードスニペットをエディタにコピーします。
    Code Snippet
    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
    CLASS lcl_plane DEFINITION. PUBLIC SECTION. TYPES: BEGIN OF ts_attributes, name TYPE string, value TYPE string, END OF ts_attributes, * declare table - do not allow the same attribute to be used more than once tt_attributes TYPE SORTED TABLE OF ts_attributes WITH UNIQUE KEY name. METHODS constructor IMPORTING iv_manufacturer TYPE string iv_type TYPE string. METHODS: get_Attributes RETURNING VALUE(rt_Attributes) TYPE tt_attributes. PROTECTED SECTION. DATA manufacturer TYPE string. DATA type TYPE string. PRIVATE SECTION. ENDCLASS. CLASS lcl_plane IMPLEMENTATION. METHOD constructor. manufacturer = iv_manufacturer. type = iv_type. ENDMETHOD. METHOD get_attributes. rt_attributes = VALUE #( ( name = 'MANUFACTURER' value = manufacturer ) ( name = 'TYPE' value = type ) ) . ENDMETHOD. ENDCLASS. CLASS lcl_cargo_plane DEFINITION INHERITING FROM lcl_plane. PUBLIC SECTION. METHODS constructor IMPORTING iv_manufacturer TYPE string iv_type TYPE string iv_cargo TYPE i. METHODS get_attributes REDEFINITION. private section. data cargo type i. ENDCLASS. CLASS lcl_cargo_plane IMPLEMENTATION. METHOD constructor. super->constructor( iv_manufacturer = iv_manufacturer iv_type = iv_type ). cargo = iv_cargo. ENDMETHOD. METHOD get_attributes. * method uses protected attributes of superclass rt_attributes = value #( ( name = 'MANUFACTURER' value = manufacturer ) ( name = 'TYPE' value = type ) ( name ='CARGO' value = cargo ) ). ENDMETHOD. ENDCLASS. CLASS lcl_passenger_plane DEFINITION INHERITING FROM lcl_Plane. PUBLIC SECTION. METHODS constructor IMPORTING iv_manufacturer TYPE string iv_type TYPE string iv_seats TYPE i. METHODS get_Attributes REDEFINITION. private section. data seats type i. ENDCLASS. CLASS lcl_passenger_plane IMPLEMENTATION. METHOD constructor. super->constructor( iv_manufacturer = iv_manufacturer iv_type = iv_type ). ENDMETHOD. METHOD get_attributes. * Redefinition uses call of superclass implementation rt_attributes = super->get_attributes( ). rt_Attributes = value #( base rt_attributes ( name = 'SEATS' value = seats ) ). ENDMETHOD. ENDCLASS.
  3. Ctrl + F3 を押してクラスを有効化します。
  4. F2 文書やナビゲーション機能などのエディタ機能を使用して、ソースコードについて理解します。

    注記

    この例には実行可能コードはありません。

抽象コンポーネントと最終コンポーネントの使用

クラスを抽象クラスとして宣言できます。つまり、プログラムでそれをインスタンス化することはできません。航空機、旅客機、および貨物機の例では、現実世界では旅客機と貨物機のみが存在すると判断する場合があります。ただし、ソフトウェアモデリングの観点からは、貨物機と旅客機の共通するコンポーネントを保持するクラス lcl_plane があると便利です。抽象クラスを使用すると、誤ってクラスのインスタンスが作成される可能性があることを心配することなく、プレーンクラスのすべての共通コンポーネントを実装できます。

クラスが抽象クラスである場合でも、その静的コンポーネントにアクセスすることができます。具体的には以下のとおりです。

  • 静的メソッド
  • 静的属性
  • 定数
  • データ型の定義

抽象クラスのメソッドを実装することはできますが、個々のメソッドを抽象メソッドとして宣言することもできます。この場合、宣言されたクラスには実装がありません。抽象メソッドは抽象クラスでのみ宣言できることに注意してください。

抽象クラスのサブクラスは、抽象メソッドが再定義された後にのみインスタンス化できます。

クラスを FINAL として宣言することができます。つまり、サブクラスを含めることはできません。

それ自体がファイナルではないクラスでは、メソッドをファイナルとして宣言することができます。つまり、クラス自体にサブクラスがある場合でも、メソッド自体を再定義することはできません。これは、メソッドに権限チェックが含まれている場合に行うことができます。そうしないと、サブクラスによってメソッドが再定義され、権限チェックが除外される可能性があります。

継承の実装

ローカルクラス LCL_PASSENGER_FLIGHTLCL_CARGO_FLIGHT には多くの共通点があり、冗長な実装が含まれています。モデルの観点から、旅客便と貨物便をフライト全般の 2 つの特殊化として認識することができます。そのため、共通の定義と実装を持つ共通のスーパークラス LCL_FLIGHT を導入します。

テンプレート:

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

ソリューション:

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

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

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

ステップ

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

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

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

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

    4. Next を選択します。

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

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

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

タスク 2: スーパークラスを定義する

新しいローカルクラス LCL_FLIGHT を定義し、ローカルクラス LCL_PASSENGER_FLIGHT および LCL_CARGO_FLIGHT が継承されるようにします。2 つのサブクラスを比較し、両方のクラスで同一の属性とメソッド定義をスーパークラスに移動します。

ステップ

  1. グローバルクラス ZCL_##_SOLUTION で、コードテンプレートを使用して新しいローカルクラス LCL_FLIGHT を定義します。

    注記

    既存のローカルクラスで参照できるように、Local Types タブでソースコードの先頭に新しいクラスを定義してください。
    1. グローバルクラス ZCL_##_SOLUTION で、Local Types タブに切り替えます。

    2. ソースコードの先頭に lcl と入力し、Ctrl + Space を押してコード完了を呼び出します。

    3. 提案完了の一覧から、lcl - ローカルクラスを選択します。

    4. lcl_ が強調表示されている間に、lcl_flight を入力して定義および実装部分のクラス名を調整します。

    5. コードテンプレートには、以下のコードが追加されている必要があります。

      ABAP
      123456789
      CLASS lcl_flight DEFINITION CREATE PRIVATE. PUBLIC SECTION. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_flight IMPLEMENTATION. ENDCLASS.
  2. LCL_FLIGHT のインスタンスを登録できないことを確認してください。

    1. CREATE PRIVATE オプションを削除し、ABSTRACT オプションに置き換えます。

    2. コードが以下のようになっていることを確認します。

      ABAP
      12
      * CLASS lcl_flight DEFINITION CREATE PRIVATE. CLASS lcl_flight DEFINITION ABSTRACT.
  3. ローカルクラス LCL_PASSENGER_FLIGHT がローカルクラス LCL_FLIGHT から継承されるようにします。

    1. ローカルクラス LCL_PASSENGER_FLIGHT の定義部分まで下にスクロールします。

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

      ABAP
      12
      CLASS lcl_passenger_flight DEFINITION INHERITING FROM lcl_flight.
  4. サブクラス LCL_PASSENGER_FLIGHT のメソッド CONSTRUCTOR の実装の先頭に super->constructor( ). を追加して、構文エラー "constructor method, instance attributes … can be be be be be only the constructor ... is been the constructor … is called." を修正します。

    注記

    この演習問題の後半では、コンストラクタロジックについて詳しく説明します。
    1. コードを以下のように調整します。

      ABAP
      12
      METHOD constructor. super->constructor( ).
  5. クイックフィックスを使用して、以下のパブリックコンポーネントをサブクラス LCL_PASSENGER_FLIGHT からスーパークラス LCL_FLIGHT に移動 ("プルアップ") します。

    • 属性 carrier_id
    • 属性 connection_id
    • 属性 flight_date
    • 構造タイプ ST_CONNECTION_DETAILS
    • メソッド GET_CONNECTION_DETAILS

    注記

    このステップでは、スーパークラス LCL_FLIGHT でまだ利用できないコンポーネントにアクセスするため、移動された GET_CONNECTION_DETAILS メソッドの実装で構文エラーが発生します。このエラーは次のステップで修正されます。
    1. ローカルクラス LCL_PASSENGER_FLIGHT の定義部分で、carrier_id にカーソルを置き、Ctrl + 1 を選択して利用可能なクイックフィックスの一覧を表示します。

    2. 利用可能なクイックフィックスの一覧から、スーパークラス lcl_flight への carrier_id のプルアップを選択します。

    3. 上記の他のコンポーネントに対してこれを繰り返します。

    4. スーパークラス LCL_FLIGHT の定義部分は以下のようになります。

      ABAP
      1234567891011121314151617181920212223
      CLASS lcl_flight DEFINITION ABSTRACT. PUBLIC SECTION. TYPES: BEGIN OF st_connection_details, airport_from_id TYPE /dmo/airport_from_id, airport_to_id TYPE /dmo/airport_to_id, departure_time TYPE /dmo/flight_departure_time, arrival_time TYPE /dmo/flight_departure_time, duration TYPE i, END OF st_connection_details. DATA carrier_id TYPE /dmo/carrier_id READ-ONLY. DATA connection_id TYPE /dmo/connection_id READ-ONLY. DATA flight_date TYPE /dmo/flight_date READ-ONLY. METHODS: get_connection_details RETURNING VALUE(r_result) TYPE st_connection_details. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS.
  6. クイックフィックスを使用して、以下のプライベートコンポーネントをサブクラス LCL_PASSENGER_FLIGHT からスーパークラス LCL_FLIGHT に移動 ("プルアップ") します。

    • 属性 planetype
    • 属性 connection_details
    1. ローカルクラス LCL_PASSENGER_FLIGHT の定義部分で、planetype にカーソルを置き、Ctrl + 1 を選択して利用可能なクイックフィックスの一覧を表示します。

    2. 利用可能なクイックフィックスの一覧から、スーパークラス lcl_flight への planetype のプルアップを選択します。

    3. 属性 connection_details に対してこれを繰り返します。

    4. スーパークラス LCL_FLIGHT の定義部分は以下のようになります。

      ABAP
      1234567891011121314151617181920212223242526
      CLASS lcl_flight DEFINITION ABSTRACT. PUBLIC SECTION. TYPES: BEGIN OF st_connection_details, airport_from_id TYPE /dmo/airport_from_id, airport_to_id TYPE /dmo/airport_to_id, departure_time TYPE /dmo/flight_departure_time, arrival_time TYPE /dmo/flight_departure_time, duration TYPE i, END OF st_connection_details. DATA carrier_id TYPE /dmo/carrier_id READ-ONLY. DATA connection_id TYPE /dmo/connection_id READ-ONLY. DATA flight_date TYPE /dmo/flight_date READ-ONLY. METHODS: get_connection_details RETURNING VALUE(r_result) TYPE st_connection_details. PROTECTED SECTION. DATA planetype TYPE /dmo/plane_type_id. DATA connection_details TYPE st_connection_details. PRIVATE SECTION. ENDCLASS.
  7. ローカルクラス LCL_CARGO_FLIGHT がローカルクラス LCL_FLIGHT から継承されるようにします。

    1. ローカルクラス LCL_CARGO_FLIGHT の定義部分までスクロールします。

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

      ABAP
      12
      CLASS lcl_cargo_flight DEFINITION INHERITING FROM lcl_flight.
  8. ローカルクラス LCL_CARGO_FLIGHT から冗長な定義をコメントまたは削除します。

    ヒント

    Problems ビューの構文エラーを使用して、冗長な定義にナビゲートします。
    1. Problems ビューで、構文エラーをダブルクリックします。"ST_CONNECTION_DETAILS" というタイプがすでに存在します

    2. ローカルクラス LCL_CARGO_FLIGHT の構造タイプ ST_CONNECTION_DETAILS の定義を削除またはコメントします。

    3. スーパークラス LCL_FLIGHT にすでに定義されている他のコンポーネントに対してこれを繰り返します。

    注記

    メソッド GET_CONNECTION_DETAILS の実装を削除またはコメントすることも忘れないでください。
  9. サブクラス LCL_CARGO_FLIGHT のメソッド CONSTRUCTOR の実装の先頭に super->constructor( ). を追加して、構文エラー "constructor method, instance attributes … can be be be be be be only to the constructor ... is been the constructor … is called." を修正します。

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

      ABAP
      12
      METHOD constructor. super->constructor( ).

タスク 3: メソッドの再定義

スーパークラスで GET_DESCRIPTION メソッドを定義し、それをサブクラスで再定義します。実装の共通部分をスーパークラスに移動し、サブクラスの特定の部分を保持します。

ステップ

  1. スーパークラス LCL_FLIGHT で、サブクラスと同じパラメータを使用してパブリックインスタンスメソッド GET_DESCRIPTION を定義します。

    ヒント

    いずれかのサブクラスからメソッド定義をコピーします。
    1. コードを以下のように調整します。

      ABAP
      123456
      CLASS lcl_flight DEFINITION ABSTRACT. PUBLIC SECTION. METHODS get_description RETURNING VALUE(r_result) TYPE string_table.
  2. ローカルクラス LCL_PASSENGER_FLIGHT および LCL_CARGO_FLIGHT で、メソッド GET_DESCRIPTION の定義を再定義に置き換えます。

    ヒント

    Problems ビューの構文エラーを使用して、メソッド定義にナビゲートします。
    1. 両方のサブクラスの定義部分で、コードを以下のように調整します。

      ABAP
      1234
      * METHODS get_description * RETURNING * VALUE(r_result) TYPE string_table. METHODS get_description REDEFINITION.
  3. クイックフィックスを使用して、新しい GET_DESCRIPTION メソッドの空の実装をローカルクラス LCL_FLIGHT に追加します。

    1. ローカルクラス LCL_FLIGHT の定義で、get_description にカーソルを置き、Ctrl + 1 を押して利用可能なクイックフィックスを呼び出します。または、コードの左側にある電球のエラーアイコンを選択することもできます。

    2. 候補リストから、get_description の実装を追加を選択します。

  4. ローカルクラス LCL_PASSENGER_FLIGHT で、メソッド GET_DESCRIPTION の実装を調整します。実装の開始時に、スーパークラスから実装を呼び出し、その結果をパラメータ r_result に格納します。

    1. 以下のコードを追加します。

      ABAP
      1
      r_result = super->get_description( ).
  5. サブクラス LCL_PASSENGER_FLIGHT から継承された属性 LCL_PASSENGER_FLIGHT の値を処理するコードをスーパークラス LCL_FLIGHT のメソッド GET_DESCRIPTION の実装に移動します。carrier_idconnection_idflight_dateconnection_details-airport_from_idconnection_details-airport_to_id、および planetype

    1. ローカル変数 txt の宣言と準備、および txt 変数と planetype 属性に対する 2 つの APPEND 文を強調表示し、Ctrl + C を押してコードスニペットをクリップボードにコピーします。

    2. Ctrl + < を押して、選択したコード行の先頭にコメント記号を追加します。

    3. ローカルクラス LCL_FLIGHT のメソッド GET_DESCRIPTION の実装に切り替え、METHOD … 命令と ENDMETHOD 命令の間にカーソルを置き、Ctrl + V を押してコードスニペットを挿入します。

    4. スーパークラスの実装は以下のようになります。

      ABAP
      12345678910111213
      METHOD get_description. DATA txt TYPE string. txt = 'Flight &carrid& &connid& on &date& from &from& to &to&'(005). txt = replace( val = txt sub = '&carrid&' with = carrier_id ). txt = replace( val = txt sub = '&connid&' with = connection_id ). txt = replace( val = txt sub = '&date&' with = |{ flight_date DATE = USER }| ). txt = replace( val = txt sub = '&from&' with = connection_details-airport_from_id ). txt = replace( val = txt sub = '&to&' with = connection_details-airport_to_id ). APPEND txt TO r_result. APPEND |{ 'Planetype:'(006) } { planetype }| TO r_result. ENDMETHOD.
  6. ローカルクラス LCL_CARGO_FLIGHT で、メソッド GET_DESCRIPTION の実装を適宜調整します。メソッド GET_DESCRIPTION の継承された実装を呼び出し、冗長な APPEND 命令を削除またはコメントします。

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

      ABAP
      123456789101112
      METHOD get_description. r_result = super->get_description( ). * APPEND |Flight { carrier_id } { connection_id } on { flight_date DATE = USER } | && * |from { connection_details-airport_from_id } to { connection_details-airport_to_id }| * TO r_result. * APPEND |Planetype: { planetype }| * TO r_result. APPEND |Maximum Load: { maximum_load } { load_unit }| TO r_result. APPEND |Free Capacity: { get_free_capacity( ) } { load_unit }| TO r_result. ENDMETHOD.

タスク 4: 共通コンストラクタの追加

スーパークラス LCL_FLIGHT で、2 つのサブクラスコンストラクタに共通する入力パラメータを持つインスタンスコンストラクタを定義します。共通パラメータが転送されるように、サブクラスのスーパークラスコンストラクタの呼出を調整します。次に、コンストラクタロジックの共通部分をサブクラスコンストラクタからスーパークラスコンストラクタに移動します。

ステップ

  1. スーパークラス LCL_FLIGHT で、サブクラス LCL_PASSENGER_FLIGHTCONSTRUCTOR と同じ入力パラメータを持つ CONSTRUCTOR メソッドを定義します。

    ヒント

    インスタンスコンストラクタメソッドのプルアップクイックフィックスはありません。代わりに、メソッド定義をサブクラスからスーパークラスにコピー & ペーストしてください。
    1. ローカルクラス LCL_PASSENGER_FLIGHT の定義部分までスクロールします。

    2. メソッド CONSTRUCTOR に対して完全な METHODS 命令を選択し、Ctrl + C を押してコードスニペットをクリップボードにコピーします。

    3. ローカルクラス LCL_FLIGHT の定義部分まで上にスクロールし、カーソルを PUBLIC SECTION 命令の後に置き、Ctrl + V を押してクリップボードからコードスニペットを挿入します。

  2. サブクラスのスーパークラスコンストラクタの呼出を調整します。インポートパラメータをスーパークラスコンストラクタに転送します。

    ヒント

    Problems ビューの構文エラーを使用して、スーパークラスコンストラクタの呼出にナビゲートします。
    1. 両方のサブクラスコンストラクタで、コードを以下のように調整します。

      ABAP
      123456
      METHOD constructor. super->constructor( i_carrier_id = i_carrier_id i_connection_id = i_connection_id i_flight_date = i_flight_date ).
  3. クイックフィックスを使用して、スーパークラスコンストラクタに空の実装を追加します。

    1. ローカルクラス LCL_FLIGHT の定義で、constructor にカーソルを置き、Ctrl + 1 を押して利用可能なクイックフィックスを呼び出します。

    2. 候補リストから Add implementation for constructor を選択します。

  4. 継承された属性 carrier_idconnection_id、および flight_date の値割当をサブクラスコンストラクタからスーパークラスコンストラクタに移動します。

    1. ローカルクラス LCL_PASSENGER_FLIGHT のメソッド CONSTRUCTOR の実装にナビゲートします。

    1. 継承された属性 carrier_idconnection_id、および flight_date の値割当を選択し、Ctrl + C を押してコードスニペットをクリップボードにコピーします。

    2. Ctrl + < を押して、選択したコード行の先頭にコメント記号を追加します。

    3. ローカルクラス LCL_FLIGHT のメソッド CONSTRUCTOR の実装に切り替え、METHOD … と ENDMETHOD の間にカーソルを置き、Ctrl + V を押してコードスニペットを挿入します。

    4. スーパークラスの実装は以下のようになります。

      ABAP
      12345
      METHOD constructor. me->carrier_id = i_carrier_id. me->connection_id = i_connection_id. me->flight_date = i_flight_date. ENDMETHOD.
    5. ローカルクラス LCL_CARGO_FLIGHT のメソッド CONSTRUCTOR の実装に切り替え、冗長な特性割当を削除またはコメントします。

  5. グローバルクラスをコンソールアプリとして有効化してテストします。ローカルクラス LCL_PASSENGER_FLIGHT のインスタンス化とメソッド GET_DESCRIPTION の呼出をデバッグします。

    1. Ctrl + F3 を押します。

    2. F9 を押します。