
编程范型
指令式
过程式
块结构
异常处理
结构化
模块化
函数式
头等函数
纯函数式
隐式
模式匹配
推导式
递归
阵列式
面向对象
基于类
基于原型
契约式
面向方面
面向代理
多态
运算符重载
泛型
多分派
元编程
宏
模板
反射式
实化
同像性
元对象
元类
面向特性
面向语言
数据流程
同步式
响应式
流处理
基于流程
宣告式
逻辑式
回答集
约束式
数据查询
框架本体
并发模型
协程
演员模型
通信顺序进程
并行模型
分叉会合
整体同步
映射归约
面向堆栈
非确定性
数据驱动
事件驱动
自动机
可微分
概率式
查论编
面向切面程序设计(Aspect-oriented programming,AOP,又译作面向方面程序设计、剖面导向程序设计),是计算机科学中的一种程序设计思想,旨在将交叉切入关注点与作为业务主体的核心关注点进行分离,以提高程序代码的模块化程度。通过在现有代码基础上增加额外的通告(Advice)机制,能够对被声明为“点切入”(Pointcut)的代码块进行统一管理与装饰,比如说:“对所有方法名以开头的方法添加后台日志”。该思想使得开发人员能够将与代码核心业务逻辑关系不那么密切的功能(如日志功能)添加至程序中,同时又不降低业务代码的可读性。
面向切面程序设计将代码逻辑切分为不同的模块(即关注点,一段特定的逻辑功能)。几乎所有的编程思想都涉及代码功能的分类,将各个关注点(Concern)封装成独立的抽象模块(如函数、过程、模块、类以及方法等),后者又可供进一步实现、封装和重写。部分关注点“交叉切入”程序代码中的数个模块,即在多个模块中都有出现,它们即被称作交叉切入关注点。
日志功能即是交叉切入关注点的一个典型案例,因为日志功能往往跨越系统中的每个业务模块,即“交叉切入”所有有日志需求的类及方法体。而对于一个信用卡应用程序来说,存款、取款、帐单管理是它的核心关注点,日志和持久化将成为交叉切入整个对象结构的交叉切入关注点。
方面的概念源于对面向对象程序设计和计算反射的融合。面向切面编程语言拥有很多类似于元对象协议的功能,但有更多的限制。方面相关的编程概念包括主题、混入和委托。使用面向切面思想的其他方式有复合过滤器和Hyper/J的hyperslices方式。
“面向切面程序设计”这一术语由施乐帕洛阿尔托研究中心的Chris Maeda首先提出,但其具体时间已经不可考证了。术语“交叉切入”是由Gregor Kiczales提出的。同许多重大的技术创新一样,面向切面程序设计,也是在不同的地方被独立发展出来。面向切面编程的早期工作,主要是由下面几个机构和人员作出的:
施乐帕洛阿尔托研究中心:Gregor Kiczales、John Lamping、Cristina Videira Lopes等人,进行的早期工作有关于反射机制和元对象协议,在1997年Gregor Kiczales发表了论文《面向切面程序设计》;代表系统是基于元对象协议的面向切面程序设计系统和AspectJ。
国际商用机器公司托马斯·J·沃森研究中心:William Harrison、Harold Ossher、Peri Tarr等人,在1980年代末进行的早期工作,有关于软件开发环境与工具集成;后来提出了多维关注点分离(MDSOC),代表系统是Hyper/J。
美国东北大学:Karl Lieberherr等人,进行的早期工作是研究软件演化,提出了得墨忒耳定律、传播模式、适应性程序设计;代表系统是Demeter/C++和Demeter/Java。
荷兰特文特大学:Mehmet Aksit等人,其代表系统是复合过滤器。
关注点是对软件工程有意义的小的、可管理的、可描述的软件组成部分,一个关注点通常只同一个特定概念或目标相关联。传统的程序设计语言,以一种线性的文本来描述软件,只采用一种方式比如类,将软件分解成模块;这导致某些关注点比较好的被捕捉,容易进一步组合、扩展;但还有一些关注点没有被捕捉,弥散在整个软件内部。
关注点分离(SOC)是标识、封装和操纵只与特定概念、目标相关联的软件组成部分的能力,即标识、封装和操纵关注点的能力。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通方面来封装、维护,这样原本分散在在整个应用程序中的变动就可以很好的管理起来。
核心关注点是一个软件最主要的关注点。在传统的程序设计语言中,将软件分解成模块的主要方式,是支配性分解,即按主关注点进行模块分解。用来描述、设计、实现一个给定关注点的软件构造单位是方法。如果两个关注点的实现的方法存在交集,则称谓这两个关注点相互交叉切入(Crosscut)。
面向切面程序设计的核心概念,是从核心关注点中分离出交叉切入关注点。面向方面编程,在支配性分解的基础上,提供叫做方面(Aspect)的一种辅助的模块化机制,这种新的模块化机制可以捕捉交叉切入关注点。
面向方面语言的通告相关构件,定义了一个接合点模型(JPM)。一个JPM定义了三种东西:
何时通告可以运行。这些叫做接合点,因为在一个运行的程序中,它们是可以有用的接合上额外行为的点。一个接合点想要有用,它必需是可寻址的,并且对普通程序员是可理解的。它还应该经历无关紧要的程序变更而保持稳定,使得一个方面经历这种变更而保持稳定。很多AOP实现支持方法执行和字段引用作为接合点。
规定(或量化)接合点的方式,这叫做点切入。点切入确定是否匹配一个给定接合点。最有用的点切入语言使用像基础语言的语法(例如AspectJ使用Java签名),并允许通过命名和组合来重新使用。
指定在接合点要运行的代码的手段。AspectJ称之为通告,并且可以在接合点之前、之后和周围运行。一些实现还支持在一个方面中定义另一个类上的一个方法。
对接合点模型进行比较可以基于:所暴露的接合点,如何规定接合点,在接合点上允许的操作,能够表达的结构性增强机制。
所有有效的Java程序也是有效的AspectJ程序,但是AspectJ容许编程者定义叫方面的特殊构造。方面包含一些对于标准类不能获得到的实体。它们是扩展方法、点切入和通告。
扩展方法允许编程者在这个方面之内向现存的类增加方法、字段或接口。下面例子向类增加一个方法(参见访问者模式):
aspect VisitAspect {
void Point.acceptVisitor(Visitor v) {
v.visit(this);
}
}
在AspectJ中接合点包括:方法或构造子调用或执行,一个类或对象的初始化,字段读或写访问,异常处理等。接合点不包括:循环、调用,子句,多个语句等。
点切入是通过组合“原始点切入指示符”(PCD)来规定的。“种类”PCD匹配特定种类的接合点(比如方法执行),并且倾向于接受类似Java签名作为输入。一个这种点切入如下所示:
execution(* set*(*))
这个点切入匹配一个方法执行接合点,如果这个方法名字开始于,并且精确的只有一个任何类型的实际参数。
“动态”PCD检查运行时间类型和绑定变量。例如:
this(Point)
这个点切入在当前执行对象是类的实例之时匹配。注意一个类的未限定名字可以通过Java的正常类型查找来使用。
“范围”PCD限制接合点的词法作用域。例如:
within(com.company.*)
这个点切入匹配在包中任何类型的任何接合点。是一种形式的通配符,它用来匹配具有一个签名的任何东西。
点切入可以复合和命名来重新使用。例如:
pointcut set() : execution(* set*(*) ) && this(Point) && within(com.company.*);
这个点切入匹配一个方法执行接合点,如果这个方法名字开始于,并且是在包中类型的实例。这个点切入可以使用名字来提及。
通告规定在(通过点切入指定的)一个接合点(之前、之后或周围)运行特定代码(指定如若一个方法中的代码)。AOP运行时间系统,在这个点切入匹配一个接合点的时候,自动调用通告。例如:
after() : 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