Posted on 2005-12-02 22:50
canonical 閱讀(673)
評論(1) 編輯 收藏 所屬分類:
設計理論
AOP作為一種新的分解與合成技術,除了性能問題之外,仍有一些概念層面上的細節問題需要解決。最近Stoerzer的一篇論文
AOP Considered harmful因為與Dijkstra的經典論文
Go To Statement Considered Harmful
進行對比而引起了廣泛的討論。
Dijkstra認為程序運行時的指令序列是我們最終想要的東西,而這一序列是運行時根據源代碼的描述在時間軸上展開的(串行結構)。因為人們更容易理解
靜態關系而不是隨時間演化的過程,所以我們應該盡量縮小靜態程序(spread out in text space)和動態過程(spread
out in time)的邏輯差距,因而我們需要使它們能夠在一個固定的坐標系統(coordinate
system)下形成對應。對于包括條件和分支語句的串行程序,我們只需要源代碼的行號(line
number)即可確定一個單一位置。在循環的情況下,我們只需要增加一個額外的循環計數器(loop
counter)即可保證可理解性。而對于子例程(procedure)調用,我們可以認為整個調用堆棧(call
stack)也構成坐標系統的一部分。goto導致一種非結構化的控制流,因而破壞了這種理解上所必需的獨立坐標系統。例如,如果一個循環中充滿了自由的
goto調轉(可能跳出循環又跳回),我們就很難確定循環變量的值到底是怎么增加的,除非我們在腦海中把源代碼運行一遍!
仿照Dijkstra的分析,Stoerzer指出AOP Advice雖然類似于procedure,但存在如下重要區別: 1. 與方法調用不同,advice執行位置在基礎源代碼中沒有標識(obliviousness of application), advice有可能在任何位置插入并改變現場變量的值 2. pointcut可能依賴運行時變量值而無法靜態計算得出(non-certainty of application)。
第一點是由AOP技術的開放性造成的,但正如面向對象中的原則: open to extension but close to modification,我們需要遵循一些原則來避免破壞原有的結構。當然,AOP應用的場景可能確實只存在著某種弱可分性,advice需要深度依賴base code中的一些特性,可能應用類似模板(template)的技術會在一定程度上緩解encapsulation breaking. AOP的開放性造成的更嚴重的問題是pointcut在演化過程中的不確定性。只有在擁有全局知識的情況下才能確認pointcut的結果正是我們所期望的。特別是重構造成方法名改變之后,pointcut無法監測這種變化。當base code修改之后,我們可能沒有意識到缺省影響到很多的aspect, 即完全理解base code變得非常困難。這種困境有一部分的原因是方法名同時作為調用標記和pointcut標記,責任過重造成的。參考一下css的選擇符
selector { property: value }
\_declaration_/
\___________ rule _________/
css可以通過選擇符應用,也可以通過指定標簽的class屬性來應用,選擇符所依靠的選擇特征也可以不僅僅是標簽名而包含屬性名等。Java最近增加了與dotNet類似的meta attribute的支持,pointcut所依賴的元數據與方法名分離之后應該可以提高pointcut的穩定性。
關于第二點,實際上OOP中的Dynamic Dispatch在某種程度上也是需要動態計算決定的,但因為接口具有明確的概念含義(an overriding method should only expect less and provide more, by maintaining all invariants),我們可以在更高的層次上理解代碼,而不需要具體到特定的實現。AOP目前可能是缺乏一些指導性的設計原則。
相對OOP而言,AOP影響到大范圍內的對象及系統的一些整體特性,因而更加需要工具的支持。