Loading AI tools
来自维基百科,自由的百科全书
特性導向程式設計(Aspect-oriented programming,AOP,又譯作面向方面程式設計、面向切面程式設計、面向方面的程式設計),是電腦科學中的一種程式設計範式,旨在將交叉切入關注與作為業務主體的核心關注進行分離,以提高程式碼的模組化程度。「方面」(aspect)通過規定叫做「點切入」(pointcut)的一種量化或查詢,在各種接合點(join point)上應用通告(advice),從而改變現有基礎代碼的行為(behavior)。比如點切入與通告的一個實例:「對所有方法名以set*
開頭的方法添加後台紀錄檔」。該范型使得開發人員能夠將與代碼核心業務邏輯關係不那麼密切的功能(如紀錄檔功能)添加至程式中,同時又不降低業務代碼的可讀性。
特性導向程式設計將代碼邏輯切分為不同的模組(即關注,一段特定的邏輯功能)。幾乎所有的編程范型都涉及代碼功能的分類,將各項關注(concern)封裝成獨立的抽象模組(如函式、過程、模組、類以及方法等),後者又可供進一步實現、封裝和重寫。部分關注「交叉切入」程式碼中的數個模組,即在多個模組中都有出現,它們即被稱作交叉切入關注。
紀錄檔功能即是交叉切入關注的一個典型案例,因為紀錄檔功能往往跨越系統中的每個業務模組,即交叉切入(crosscut)所有有紀錄檔需求的類及方法體。而對於一個信用卡應用程式來說,存款、取款、帳單管理是它的核心關注,紀錄檔和持久化將成為交叉切入整個對象結構的交叉切入關注。
方面的概念源於對物件導向程式設計和計算反射的融合。特性導向程式設計語言擁有很多類似於元對象協定的功能,但有更多的限制。方面相關的編程概念包括主題、混入和委託。使用面向方面范型的其他方式有複合過濾器和Hyper/J的hyperslices方式。
「特性導向程式設計」這一術語由全錄帕洛阿爾托研究中心的Chris Maeda首先提出,但其具體時間已經不可考證了。術語「交叉切入」(crosscut)是由Gregor Kiczales提出的。同許多重大的技術創新一樣,特性導向程式設計,也是在不同的地方被獨立發展出來。特性導向程式設計的早期工作,主要是由下面幾個機構和人員作出的:
關注是對軟體工程有意義的小的、可管理的、可描述的軟體組成部分,一項關注通常只同一個特定概念或目標相關聯。傳統的程式語言,以一種線性的文字來描述軟體,只採用一種方式比如類,將軟體分解成模組;這導致某些關注比較好的被捕捉,容易進一步組合、擴充;但還有一些關注沒有被捕捉,彌散在整個軟體內部。
關注分離(SOC)是標識、封裝和操縱只與特定概念、目標相關聯的軟體組成部分的能力,即標識、封裝和操縱關注的能力。分離關注使得解決特定領域問題的代碼從業務邏輯中獨立出來,業務邏輯的代碼中不再含有針對特定領域問題代碼的呼叫,業務邏輯同特定領域問題的關係通方面來封裝、維護,這樣原本分散在在整個應用程式中的變動就可以很好的管理起來。
核心關注是一個軟體最主要的關注。在傳統的程式語言中,將軟體分解成模組的主要方式,是支配性分解,即按主關注進行模組分解。用來描述、設計、實現一項給定關注的軟體構造單位是方法。如果兩個關注的實現的方法存在交集,則稱謂這兩個關注相互交叉切入(crosscut)。
特性導向程式設計的核心概念,是從核心關注中分離出交叉切入關注。特性導向程式設計,在支配性分解的基礎上,提供叫做方面(aspect)的一種輔助的模組化機制,這種新的模組化機制可以捕捉交叉切入關注。
特性導向程式設計語言的通告相關構件,定義了一個接合點模型(JPM)。一個JPM定義了三種東西:
對接合點模型進行比較可以基於:所暴露的接合點,如何規定接合點,在接合點上允許的操作,能夠表達的結構性增強機制。
所有有效的Java程式也是有效的AspectJ程式,但是AspectJ容許編程者定義叫方面的特殊構造。方面包含一些對於標準類不能獲得到的實體。它們是擴充方法、點切入和通告。
擴充方法允許編程者在這個方面之內向現存的類增加方法、欄位或介面。下面例子中,方面VisitAspect
向類Point
增加一個acceptVisitor
方法(參見訪問者模式):
aspect VisitAspect {
void Point.acceptVisitor(Visitor v) {
v.visit(this);
}
⋮
}
在AspectJ中接合點包括:方法或構造子呼叫或執行,一個類或對象的初始化,欄位讀或寫訪問,例外處理等。接合點不包括:迴圈、super
呼叫,throw
子句,多個語句等。
點切入是通過組合「原始點切入指示符」(PCD - primitive pointcut designator)來規定的。例如:
aspect VisitAspect {
⋮
pointcut set() : execution(* set*(*) ) && this(Point) && within(com.company.*);
⋮
}
這個點切入匹配一個方法執行接合點,如果這個方法名字開始於set
,並且此對象(this
)是在com.company
包中類型Point
的實例。這個點切入可以使用名字set()
來提及。點切入可以複合和命名來重新使用。
「種類」PCD匹配特定種類的接合點(比如方法執行),並且傾向於接受類似Java模樣的簽章作為輸入:
execution(* set*(*))
這個點切入匹配一個方法執行接合點,如果這個方法名字開始於set
,並且精確的只有一個任何類型的實際參數。
「動態」PCD檢查執行時間類型和繫結變數:
this(Point)
這個點切入在當前執行對象是類Point
的實例之時匹配。注意一個類的未限定名字可以通過Java的正常類型尋找來使用。
「範圍」PCD限制接合點的詞法作用域:
within(com.company.*)
這個點切入匹配在com.company
包中任何類型的任何接合點。*
是一種形式的萬用字元,它用來匹配具有一個簽章的任何東西。
通告規定在(通過點切入指定的)一個接合點(之前、之後或周圍)執行特定代碼(指定如若一個方法中的代碼)。特性導向程式設計的執行時間系統,在這個點切入匹配一個接合點的時候,自動呼叫通告。例如:
aspect VisitAspect {
⋮
after() : set() {
Display.update();
}
}
這在效果上指定了:「如果set()
點切入匹配這個接合點,在接合點完成之後,執行代碼Display.update()
。」
下列程式語言已經實現了AOP,於語言之內或外部庫:
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.