轉自:http://jgtang82.iteye.com/blog/114737
SAP BAdI 實現原理解析
關鍵字: badi, adapter, proxy, factory
最近幾天發現這篇文章被單擊的次數比較高, 這裡把文檔內容再充實一下:
本文談得是SAP BAdI 機制背後的一些設計問題, 關於如何使用BAdI請參考:
...
在SAP系統中 BAdI 相關類的 類圖 如下:
下面能過程式碼分析 BAdI 機制背後的一些設計問題:
1. 定義指向BAdI interface的Reference
DATA: exit_ref TYPE REF TO ZIF_EX_BADI.
2. 獲得繼承BAdI interface的子類執行個體
CALL METHOD cl_exithandler=>get_instance
CHANGING
instance = exit_ref.
這裡的cl_exithandler=>get_instance方法是一個簡化的Abstract Factory.
a) 為什麼說它是個簡化的Abstract Factory呢? 因為CL_EXITHANDLER沒有一個抽象的工廠類, 只有一個產品簇, 只完成單一的建立工作。
b) 為什麼不說它是個Factory Method? 是因為它沒把類的建立工作延遲到子類。
c) 為什麼cl_exithandler=>get_instance要用原廠模式呢?
在Client代碼端看來,通過調用get_instance這個方法就可以得到具體實作類別執行個體,然後調用下面的方法:
CALL METHOD exit_ref->CUSTOM_VALIDATION
IMPORTING
param = 'xxx'
EXPORTING
flt_val = 'xxx'.
就調用到實作類別中的介面方法了。
但通過Debug代碼你會發現這個調用返回的是Adapter Class 'ZCL_EX_BADI'而非我們的Impl Class!
其實這就是建立型模式的意義 - 隱藏對象的建立細節.
也就是說當我們調用CUSTOM_VALIDATION時,其實是調用了ZCL_EX_BADI->CUSTOM_VALIDATION.
3. ZCL_EX_BADI->CUSTOM_VALIDATION,這個方法是SAP系統自動產生的,核心代碼如下:
- ...
- LOOP AT INSTANCE_BADI_TABLE ASSIGNING <exit_obj></exit_obj>
WHERE METHOD_NAME = 'DISPLAY'.
- APPEND TO EXIT_OBJ_TAB.
- ENDLOOP.
- ...
- LOOP at exit_obj_tab ASSIGNING <exit_obj></exit_obj>
WHERE ACTIVE = SXRT_TRUE.
- CHECK <exit_obj></exit_obj>-imp_class NE old_imp_class.
- <flt_cache_line></flt_cache_line>-valid = sxrt_true.
- flt_val_db = <exit_obj></exit_obj>-flt_val.
- ...
- MOVE <exit_obj></exit_obj>-imp_class to <flt_cache_line></flt_cache_line>-imp_class.
- MOVE <exit_obj></exit_obj>-imp_switch to <flt_cache_line></flt_cache_line>-imp_switch.
- MOVE <exit_obj></exit_obj>-order_num to <flt_cache_line></flt_cache_line>-order_num.
- INSERT INTO TABLE INSTANCE_FLT_CACHE.
- old_imp_class = <exit_obj></exit_obj>-imp_class.
- ENDLOOP.
- ...
- LOOP AT INSTANCE_FLT_CACHE ASSIGNING <flt_cache_line></flt_cache_line>
- WHERE flt_name = flt_name
- AND valid = sxrt_true
- AND method_name = 'CUSTOM_VALIDATION'.
- ...
- CALL METHOD ('CL_FOBU_METHOD_EVALUATION')=>load
- EXPORTING
- im_class_name = <flt_cache_line></flt_cache_line>-imp_class
- im_interface_name = 'ZIF_EX_BADI'
- im_method_name = 'CUSTOM_VALIDATION'
- RECEIVING
- re_fobu_method = <flt_cache_line></flt_cache_line>-eo_object
- EXCEPTIONS
- not_found = 1
- OTHERS = 2.
- ...
- ENDLOOP.
這時我們會發現這段代碼會找到所有Active的BAdI Implemention然後去執行它。這裡有點Adpater的味道而且在SAP標準文檔中確實是把ZCL_EX_BADI 類為Adapter Class, 但是我覺得這個叫法不合適,改變介面不是這個類的主要價值,裡面的Loop調用實作類別方法和Filter顯得更主要。所以它的主要價值應該是對實作類別的存取控制,改稱Adapter Class為 Proxy或許更合適。下面是Proxy模式的類圖:
關於Proxy模式, 《Head First Design Pattern》中講的非常不錯,這裡推薦一下。
總結:
1. 通過 Factory 獲得Adapter Class 的執行個體 (障眼法 / 封裝建立細節)
2. 通過 Proxy 對象(Adapter Class) 實現對 BAdI Implementations 的存取控制