iT邦幫忙

2024 iThome 鐵人賽

DAY 13
0
自我挑戰組

ABAP 基礎30天學習筆記系列 第 13

Day13_定義與呼叫方法

  • 分享至 

  • xImage
  •  

原文連結:Defining and Calling Methods

宣告方法

今天緊接著要來在calss內宣告方法。方法有分靜態方法(CLASS-METHODS)跟動態方法(METHODS)。下面為一個方法的宣告結構,在方法名稱後包含了要傳遞的參數以及例外宣告,每個參數都包含了名稱與型態,可以分成以下四種:

CLASS <class_name> DEFINITION.
  <any>SECTION. "這裡是任意SECTION的宣告
  
  METHODS <method_name>
      "導入參數"
      IMPORTING  <input_1>  TYPE<type>
                 <input_2>  TYPE<type> DEFAULT <val>
                 ...
     "導出參數"
     EXPORTING   <output_1> TYPE<type>
                 ...
     "變更參數"
     CHANGING    <inout_1>  TYPE <type> OPTIONAL
                 ...
    "返回參數"
    RETURNING VALUE(result)  TYPE<type>
    RAISING  <excepyion1>
             <excepyion2>
             ...
ENDCLASS.
  1. 導入參數 Importing Parameters
    從呼叫端可以取得的值,數量不限。
    預設上,填入導入參數值是必要的,但是有兩個方式會讓導入參數值變成可選項:
    1.OPTIONAL註記,此時初始參數值將自動設為適合該參數的預設值
    2.DEFAULT <val>註記,將根據的型別賦予初始值
    如果變更了導入參數的位置,可能導致語法錯誤。

  2. 導出參數Exporting Parameters
    為方法的回傳結果,一樣數量不限。所有導出參數的值都是可選的。

  3. 變更參數 Changing Parameters
    同樣是用來取得呼叫端提供的值,但與導入參數不同的是,函式可以對變更參數進行變更。數項不限且強制填值,但一樣可以參考導入參數,將填入值改成可選項。

  4. 返回參數 Returning Parameters
    返回參數是函式運算的結果,但可以直接在表達式中使用。一個函式中僅能有一個返回參數,且必須使用pass-by-value,這種形式的參數傳遞被包圍在不含空格的括號中,並前綴VALUE

  5. 例外狀況
    RAISING則用於列出函式運行時可能出現的例外狀況跟錯誤。

範例

CLASS lcl_connection DEFINITION.
  PUBLIC SECTION.
  ...
* 方法宣告(導入參數)
    METHODS set_attributes
      IMPORTING
        i_carrier_id    TYPE /dmo/carrier_id  OPTIONAL
        i_connection_id TYPE /dmo/connection_id.

* 方法宣告(導出參數)
    METHODS get_attributes
      EXPORTING
        e_carrier_id    TYPE /dmo/carrier_id 
        e_Connection_id TYPE /dmo/connection_id.
    
* PROTECTED SECTION.
* PRIVATE SECTION.

ENDCLASS.

如範例所示,在class lcl_connection中,分別用兩個不同的方法來導入與導出參數。

只要在 class 的 define 部分有宣告的函式,都必須在下一段的 implementation 部分裡建立對應的實體,否則會出現語法錯誤喔!

建立方法實體

CLASS lcl_connection IMPLEMENTATION.

* 建立實體,輸入參數
METHOD set_attributes.
    carrier_id = i_carrier_id.
    connection_id = i_connection_id.
ENDMETHOD.
    
* 建立實體,輸出參數
METHOD get_attributes.
        e_carrier_id  = carrier_id.
        e_connection_id = connection_id.

ENDCLASS.

上例由前面定義的方法來建立實體,在Implementation區塊,使用METHOD <method_name>ENDMETHOD.將方法建立成建立函式實體。

和前一章不同,由於這裡的函式賦值時已在class內,故不需要屬性選擇器來指定class。

只要先前有定義過的方法都需要建立實體,並且可以存取先前所宣告的變數。但靜態方法僅能存取靜態參數。並且可以不使用參照變數及->,=>等識別符就訪問class裡的屬性。

ME 自我呼叫

如同其他程式語言的this用於自我呼叫,ABAP 提供作用於方法實例裡的 built-in 變數 MEME是一種參照變數,型別參照當前的class,且其位址與當前實體的位置一致,建議上會盡量避免使用,除非有物件的屬性會名稱產生衝突。

*假設class內有變數與方法內變數撞名
DATA carrier_id    TYPE /dmo/carrier_id.
DATA connection_id TYPE /dmo/connection_id.

...
    
METHODS set_attributes
      IMPORTING
        i_carrier_id    TYPE /dmo/carrier_id
        i_connection_id TYPE /dmo/connection_id.

* 在函式實體中使用ME來避免混淆
METHOD set_attributes.
    me->carrier_id = carrier_id.
    me->connection_id = connection_id.
ENDMETHOD. 

在範例中,set_attributes( ) 的導入參數剛好和上面建立的物件屬性名稱相同,這時就可使用ME來指定原先建立的內建參數避免混淆,並以->連接變數名稱。

例外狀況

* 定義例外
RAISE EXCEPTION TYPE <exception_class>.
* 實例化例外
METHOD set_attributes.
    IF carrier_id IS INITIAL OR connection_id IS INITIAL.
      RAISE EXCEPTION TYPE cx_abap_invalid_value.
    ENDIF.
    
    me->carrier_id = carrier_id.
    me->connection_id = connection_id.
ENDMETHOD. 

當方法內的例外事件發生,通常會用if指定觸發條件,再透過RAISE EXCEPTION TYPE呼叫例外狀況。技術上而言,例外的名稱會是ABAP中特殊例外class的名稱,並透過RAISE EXCEPTION TYPE建立該例外class的實體。

一旦例外事件發生,整個程式就會停止執行。只有當三個先決條件都被滿足時,控制權才會返回給呼叫的程式,否則會直接進runtime error。先決條件包含:

  1. 在RAISING 裡有宣告該例外
  2. 該方法呼叫時,被包圍在TRY … ENDTRY結構中
  3. 該 TRY … ENDTRY 結構中有使用 CATCH區塊指定例外事件

具體 TRY CATCH 寫法會在後續的實作階段提及。

函式呼叫

* 動態函式
<reference_variable>-><method_name>(
    EXPORTING  <input_1>  = <expression>
               <input_2>  = <expression>
               ...
    IMPORTING  <output_1>  = <variable>
               ...
    CHANGING   <inout_1>  = <variable>
               ...
    ).
* 靜態函式
<class_name>=><static_methood>( ... ).

如上例所示,根據是否為靜態方法分別用->=>(無空格)對函式進行呼叫,並且參數包含在括號中,若無,則括號內至少要有一個空格

注意,在呼叫方法時,EXPORTINGIMPORTING關鍵字底下的參數類型(導入/導出)與關鍵字的動作是相反的。原因是我們要「傳出(EXPORTING)」「導入參數(input parameter)」供其他方法使用,並且「接收(IMPORTING)」其他程式的「導出參數(output)」,我自己是記"導入(呼叫端的)參數"以及"(從呼叫端)導出(的)參數"。寫法如下:

範例

* 呼叫函式
* 於`IMPORTING`字段,將參數從呼叫端導出,並"接收"回傳的值至函式的導出參數中
connection->get_attributes(
    IMPORTING
        e_carrier_id  = carrier_id
        e_connection_id = connection_id ).
* 呼叫函式
* 於`EXPORTING`字段,將函式的導入參數值"輸出",導入至呼叫端中
connection->set_attributes(
    EXPORTING
    i_carrier_id = 'LH'
    i_connection_id = '0400').

另外,由於EXPORTING區塊的導入參數會直接被呼叫端導入,對導入參數賦值時可以使用表達式語法,只要資料型別與原始參數相符即可;但傳入的導出參數及變更參數必須使用陳述式,一樣要注意型別。

"EXPORTING" 導入參數的簡化寫法

前面說過,方法中關鍵字IMPORTING是強制要有的,然而接收導入參數的EXPORTING則是可選項。在ABAP中,有幾種省略的寫法:

  1. 正常寫法
connection->set_attributes(
  EXPORTING
    carrier_id = 'LH'
    connection_id = '0400').
  1. 當方法中只有導入參數時,可以直接省略EXPORTING關鍵字。
connection->set_attributes(
    carrier_id = 'LH'
    connection_id = '0400').
  1. 只有一個強制的導入參數時,可以直接省略EXPORTING關鍵字以及參數名稱。
connection->set_attributes('0400').

引發例外

在稍早我們知道了如何在定義時用if … RAISE EXCEPTION TYPE定義例外,而在呼叫時,使用TRY … ENDTRYCATCH來定義例外,在CATCH後要接想觸發的例外名稱(名稱宣告在class定義時的RAISING區段中)。

* 呼叫函式(主程式)
 TRY.
        connection->set_attributes(
          EXPORTING
            i_carrier_id    = c_carrier_id
            i_connection_id = c_connection_id
        ).

        APPEND connection TO connections.
        out->write( `Method call successful` ).
CATCH cx_abap_invalid_value.
        out->write( `Method call failed`     ).
ENDTRY.  

上述範例為主程式,如果 i_carrier_idi_connection_id這兩個參數在賦值時出現型別錯誤,就會觸發例外警示。

* 定義方法(位於LocalType)
CLASS lcl_connection DEFINITION.
  PUBLIC SECTION.

* 屬性宣告
    DATA carrier_id    TYPE /dmo/carrier_id.
    DATA connection_id TYPE /dmo/connection_id.

* 方法宣告
    METHODS set_attributes
      IMPORTING
        i_carrier_id    TYPE /dmo/carrier_id  DEFAULT 'LH'
        i_Connection_id TYPE /dmo/connection_id
      RAISING
        cx_abap_invalid_value.

ENDCLASS.

* 實例化函式
CLASS lcl_connection IMPLEMENTATION.

  METHOD set_attributes.
    "設置觸發條件"
    IF i_carrier_id IS INITIAL OR i_connection_id IS INITIAL.
      RAISE EXCEPTION TYPE cx_abap_invalid_value.
    ENDIF.

    carrier_id    = i_carrier_id.
    connection_id = i_connection_id.

  ENDMETHOD.

ENDCLASS.

第二段是LocalType裡的自訂義Class connection,也就是宣告該方法的地方。這個範例中的參數、方法及例外都是宣告在connection之中,RAISING區段裡有先宣告好cx_abap_invalid_value這個例外變數。

函數式方法(Functional Methods)與回傳值

當一個方法具有回傳值(returning parameter),可以稱為函數式方法。不能在同一個函數式中定義多個回傳值,且需強制回傳任意值。

雖然函數式可以搭配多種參數,但多半只與導入參數(import method)一起使用,因為加入導出參數與變化參數會失去其最大優勢--直接在其他ABAP表達式中使用函數式的回傳結果。

*方法定義
METHODS get_output
    RETURNING VALUE(r_output) TYPE string_table.
* 範例一
DATA(result) = connection->get_output( ).
* 範例二
out->write( data = connection->get_output()
            name = ` ` ).

在上例中,可以看到兩種透過表達式使用函數方法的範例:第一個範例是直接將回傳值賦值給變數,第二個範例則是直接把回傳值作為另一個方法的輸入值(範例中為write方法)。

這篇因為各種程式碼範例,實在是有夠長...接下來要講到如何封裝方法了!


上一篇
Day12_建立ABAP class實體
下一篇
Day14_用封裝確保一致性
系列文
ABAP 基礎30天學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言