面向切面的程序設計

-{zh-hans:面向方面編程;zh-hant:剖面導向程式設計;zh-tw:特性導向程式設計;}-（Aspect-oriented programming，AOP，又譯作面向方面程序設計、面向切面程序設計、-{zh-hans:剖面導向程序設計;zh-hant:面向方面的程式設計;}-），是計算機科學中的一種編程範型，旨在將交叉切入關注與作為業務主體的核心關注進行分離，以提高程序代碼的模塊化程度。“方面”（aspect）通過規定叫做“點切入”（pointcut）的一種量化或查詢，在各種接合點（join point）上應用通告（advice），從而改變現有基礎代碼的行為（behavior）。比如點切入與通告的一個實例：“對所有方法名以set*開頭的方法添加後臺日誌”。該思想使得開發人員能夠將與代碼核心業務邏輯關係不那麼密切的功能（如日誌功能）添加至程序中，同時又不降低業務代碼的可讀性。

**簡介**
面向方面編程將代碼邏輯切分為不同的模塊（即關注，一段特定的邏輯功能）。幾乎所有的編程思想都涉及代碼功能的分類，將各項關注（concern）封裝成獨立的抽象模塊（如函數、過程、模塊、類以及方法等），後者又可供進一步實現、封裝和重寫。部分關注“交叉切入”程序代碼中的數個模塊，即在多個模塊中都有出現，它們即被稱作交叉切入關注。
日誌功能即是交叉切入關注的一個典型案例，因為日誌功能往往跨越系統中的每個業務模塊，即交叉切入（crosscut）所有有日誌需求的類及方法體。而對於一個信用卡應用程序來說，存款、取款、帳單管理是它的核心關注，日誌和持久化將成為交叉切入整個對象結構的交叉切入關注。
方面的概念源於對面向對象編程和計算反射的融合。面向方面編程語言擁有很多類似於元對象協議的功能，但有更多的限制。方面相關的編程概念包括主題、混入和委託。使用面向方面範型的其他方式有Composition filters和Hyper/J的hyperslices方式。

**歷史**
“面向方面編程”這一術語由施樂帕洛阿爾託研究中心的Chris Maeda首先提出，但其具體時間已經不可考證了。術語“交叉切入”（crosscut）是由Gregor Kiczales提出的。同許多重大的技術創新一樣，面向方面編程，也是在不同的地方被獨立發展出來。面向方面編程的早期工作，主要是由下面幾個機構和人員作出的：
*施樂帕洛阿爾託研究中心：Gregor Kiczales、John Lamping、Cristina Videira Lopes等人，進行的早期工作有關於反射機制和元對象協議，在1997年Gregor Kiczales發表了論文《面向方面編程》；代表系統是基於元對象協議的面向方面編程系統和AspectJ。
*國際商用機器公司Thomas J. Watson Research Center：William Harrison、Harold Ossher、Peri Tarr等人，在1980年代末進行的早期工作，有關於軟件開發環境與工具集成；後來提出了多維關注分離（MDSOC），代表系統是Hyper/J。
*美國東北大學：Karl Lieberherr等人，進行的早期工作是研究軟件演化，提出了得墨忒耳定律、傳播模式、適應性編程；代表系統是Demeter/C++和Demeter/Java。
*荷蘭特文特大學：Mehmet Aksit等人，其代表系統是Composition filters。

**基本概念**
關注是對軟件工程有意義的小的、可管理的、可描述的軟件組成部分，一項關注通常只同一個特定概念或目標相關聯。傳統的編程語言，以一種線性的文本來描述軟件，只採用一種方式比如類，將軟件分解成模塊；這導致某些關注比較好的被捕捉，容易進一步組合、擴展；但還有一些關注沒有被捕捉，彌散在整個軟件內部。
關注分離（SOC）是標識、封裝和操縱只與特定概念、目標相關聯的軟件組成部分的能力，即標識、封裝和操縱關注的能力。分離關注使得解決特定領域問題的代碼從業務邏輯中獨立出來，業務邏輯的代碼中不再含有針對特定領域問題代碼的調用，業務邏輯同特定領域問題的關係通方面來封裝、維護，這樣原本分散在在整個應用程序中的變動就可以很好的管理起來。
核心關注是一個軟件最主要的關注。在傳統的編程語言中，將軟件分解成模塊的主要方式，是支配性分解，即按主關注進行模塊分解。用來描述、設計、實現一項給定關注的軟件構造單位是方法。如果兩個關注的實現的方法存在交集，則稱謂這兩個關注相互交叉切入（crosscut）。
面向方面編程的核心概念，是從核心關注中分離出交叉切入關注。面向方面編程，在支配性分解的基礎上，提供叫做Aspect (computer programming)（aspect）的一種輔助的模塊化機制，這種新的模塊化機制可以捕捉交叉切入關注。

**接合點模型**
面向方面編程語言的通告相關構件，定義了一個接合點模型（JPM）。一個JPM定義了三種東西：
#何時通告可以運行。這些叫做接合點，因為在一個運行的程序中，它們是可以有用的接合上額外行為的點。一個接合點想要有用，它必需是可尋址的，並且對普通程序員是可理解的。它還應該經歷無關緊要的程序變更而保持穩定，使得一個方面經歷這種變更而保持穩定。很多AOP實現支持方法執行和字段引用作為接合點。
# 規定（或量化）接合點的方式，這叫做點切入。點切入確定是否匹配一個給定接合點。最有用的點切入語言使用像基礎語言的語法（例如AspectJ使用Java簽名），並允許通過命名和組合來重新使用。
# 指定在接合點要運行的代碼的手段。AspectJ稱之為通告，並且可以在接合點之前、之後和周圍運行。一些實現還支持在一個方面中定義另一個類上的一個方法。
對接合點模型進行比較可以基於：所暴露的接合點，如何規定接合點，在接合點上允許的操作，能夠表達的結構性增強機制。

**AspectJ的接合點模型**
所有有效的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，於語言之內或外部庫：
*.NET Framework語言（C# / VB.NET）
**PostSharp，是一個商業AOP實現，具有免費但有限制的版本。
**Unity，提供到在核心編程領域包括數據訪問、安全性、日誌、異常處理和其他之中經過實踐檢驗的設施的API。
*ActionScript
*Ada
*AutoHotkey
*C / C++
*COBOL
*The Cocoa Objective-C框架
*ColdFusion
*Common Lisp
*Delphi
*Delphi Prism
*e（IEEE 1647）
*Emacs Lisp
*Groovy
*Haskell
*Java
**AspectJ
**Spring Framework
*JavaScript
*Logtalk
*Lua
*make
*Matlab
*ML
*Perl
*PHP
*Prolog
*Python
*Racket
*Ruby
*Squeak Smalltalk
*UML 2.0
*XML

**參考文獻**

**站外鏈接**
  Aspect-Oriented Software Development-  Aspect-Oriented Software Development（AOP年會）-  AOSD Wiki date=20080517085216 （英文維基給AOP的專欄）-  AspectJdate=20110819202401 （Java的實現）
**  date=20200219132654  更多有關於型態間成員宣告的資料-  關於面向側面的編程和AspectJ的系列文章-  The AspectBench Compiler for AspectJ（另一個Java實現）-  一篇深度討論AOP與AspectJ的系列文章-  利用RemObject Taco實現AOP的文章-  Constraint-Specification Aspect Weaver date=20071026060419 -  面向側面對物件導向：該用哪個？何時使用？ date=20210415064448 -  給Python用的AOP輕量實現-  LOOM.NET date=20080827215106 -  剖面導向程式設計(AOP/AOSD)簡介 date=20150923211641