• 沒有找到結果。

3.2 設計原理

3.2.1 AspectW 核心原理

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

3.2 設計原理

這一章節將討論 AspectW 設計的原理。AspectW 延用了 AspectF 原有的核心碼,一開始 計劃再精鍊但仔細檢查並測試後,認為延用是最好的策略。曾嘗試過幾次核心碼的調 整,事後認為沒有原本的好,還不如就保有原創也向原作者致敬。

然而在剖面功能指令部份,仔細試用一陣子後,認為是原作者為當時專案需要特 製,不易一般化的應用。AspectF 本身已內附了 retry 功能,在試用好幾次後發現若使 用原有設計代入補獲與重試機制會有些冗餘也有些不足。在多日考量下決定重製,延用 原有核心碼而剖面功能(aspect function)部份以補獲與重試應用為主。

3.2.1 AspectW 核心原理

在開始前先從一個使用範例開始,先了解語法結構,主功能邏輯、剖面功能與縫合區組 織成一體後的模樣。如圖 3-7,此例的程式語言是 C#,沒有使用 Attribute 也不用為了 縫合另外建立剖面類別,可以直接把目標程式碼區塊包裹住,跟它縫合的剖面功能也能 傳入參數。

圖 3.7 一個 AspectW 使用範例

1. 沒有複雜的技術,沒有 Attributes, ContextBoundObject, Post build event, IL Manipulation, Dynamic Proxy。

2. 效能幾乎沒有損失。 Combine 這是最重要的核心之一,它負責縫合剖面功能全部串成一個鏈(chain),後面再 對它詳細介紹。介紹一下參數 work 它代表了被包裹住的程式碼區塊。傳入的二個參數

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

中的 aspect 是在使用時由“AspectW.Define”所建構出來的,它是動態產生的物件每 Define 一次就建構一個實體出來。另一個參數 traceBefore,它的型別是 Action,以程 式語言 C 來看就是函式指標(function pointer), JavaScript 來看是函式物件

(function object)。Action 是.NET Framework 裡較新的技術,它是個特別的類別,對 它最快的理解就是個 delegate,更好的比喻是 lambda expression。在例子裡

traceBefore 參數可以看做是指向“InsertLog("Inserting customer the easy way")”

函式的指標。把這些資訊組合起來,TraceBefore 的功能就是在執行被包裹的程式碼區 塊的程式前,先去調用(invoke) traceBefore 函式,也就是“InsertLog("Inserting customer the easy way")”。

圖 3.8 剖面功能 TraceBefore 原始碼

圖 3.9 剖面功能 RetryOnce 原始碼

// around

// before // after

// exception

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

以剖面功能 TraceBefore 原始碼為基礎開始,再來閱讀另一個剖面功能函式 RetryOnce 原始碼應該就快速多了。請參考圖 3.9 剖面功能 RetryOnce 原始碼。

其原始碼中有 try-catch 語法結構,整體語意是這樣的:執行被包裹的程式碼區塊 work,若失敗的話稍停一段時間後,此例是 1000 豪秒(1 秒),再重新執行一次被包裹的 程式碼區塊。選取此例的因另一個原因是此例可以一眼清楚的看出在 joint point,也 就是 work,的“before”、“after”、“around”還有“exception”的位置點,可以 依需要把程式碼加上。

接下來可以讀取最核心的部份之一 Combine 函式,它負責縫合的工作。請看圖 3.10,閱讀原始碼可以看到 AspectW 有個成員變數 Chain,這個 Chain 存放串聯好的剖 面功能。Combine 函式的功能是依順序串聯所有的剖面功能,換句話說,Combine 函式 就是縫合所有欲修飾或新增特徵或加入非主功能機制到被包裹的程式碼區塊。

再看另一個核心 Do 函式,請看圖 3.11 另一核心 Do 函式原始碼。Do 函式負責執行 經由 Combine 函式縫合好的剖面功能鏈。在細讀 Do 函式的原始碼時,先細看一下其中 有個名為 Chain 的屬性,它也是核心之一,其型態是:

“Action<Action>”

圖 3.10 核心原始碼之一 Combine 函式原始碼

當中,這個 Action<T>型別是個函數的泛型,於.Net Framework 2.0 版以後開始發 展,不過在.Net Framework 3.5 版以後才成熟。Action 也可以說就是 Delegate,若用 C 語言的角度來看則是一個函式指標(function pointer)。在理解上,可以用 lambda expression 來理解,可以看作在 FL(function language)的 f(g(x))描述句。

在這個“Action<Action>”結構下 Chain 就可以不斷的串聯 Action 。而這裡的 Action 其實就是前面提到多次的剖面功能(aspect function),也就是 Combine 函式可以縫合剖面 功能的原理。理解了 Chain 結構後,再來閱讀 Do 函式就快多了。從技術面來閱讀:若 Chain 沒有任何串聯 Action 那就直接調用 work 函 式;否則就依序由外向內一層層調用 Action 最 後才調用 work 函式。再注意一點,此 work 其 實也是一個 Action。改以使用面來閱讀:若沒 有縫合剖面功能則執行被包裹的主功能程式 碼,否則依序執行剖面功能最後再執行被包裹

的主功能程式碼。請注意 work 函式也就是主功能程式碼。

整理一下,AspectW 最主要的核心有三個:Chain、Combine、Do,而串聯這三個核 心的基本原理是 FL 的 lambda expression。其它重要部份,如“AspectW.Define”其中的 Define 有語法包裝用途,內容是建構式,其效果在語法上有宣示的意味,宣示在其下將 要包裹一段程式碼區塊為其加入一個或數個剖面功能。

AspectW 語法

圖 3.11 核心原始碼之一 Do 函式原始碼

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

接下來,用 EBNF 格式重新寫下 AspectW 的使用語法,如圖 3.12 AspectW 基礎法。

其實 AspectW 的語法與 AspectF 是一樣的因為核心基礎是一致的。

首先用“AspectW.Define”進行宣示,再來可以先寫下 Do 敘述先包裹好目標程式碼 區塊,也就是主功能邏輯,然後再一一加入需要的剖面功能,也就是非主要功能機制。

其中<Aspect-Function>是剖面功能,實現非主功能機制,其實體是 Action。Action 是個特別的類別可以理解成“函式指標”,在 C#裡 class method 也是 Action,Delegate 也是 Action。在 Do 函式的符號“()=>”表示這是一個 Delegate,用來接連一個 lambda expression 敘述句。<Logic-Function-Block>放的就是主功能邏輯,其實體就是程式語 言敘述句的集合。

圖 3.12 AspectW 基礎語法

AspectW 的核心碼還有另一個 Return 函式,這個函式是 Do 函式的延伸,目的是當 被包裹的程式碼區塊有回傳(return)的情境時使用。在使用上把 Do 置換成 Return 並對 應好回傳的泛型類別即可。在此就不再細述。

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y