编程范型 |
---|
面向切面的程序设计(Aspect-oriented programming,AOP,又译作面向方面的程序设计、剖面导向程序设计),是计算机科学中的一种程序设计思想,旨在将横切关注点与业务主体进行进一步分离,以提高程序代码的模块化程度。通过在现有代码基础上增加额外的通知(Advice)机制,能够对被声明为“切点(Pointcut)”的代码块进行统一管理与装饰,比如说:“对所有方法名以set*
开头的方法添加后台日志”。该思想使得开发人员能够将与代码核心业务逻辑关系不那么密切的功能(如日志功能)添加至程序中,同时又不降低业务代码的可读性。面向切面的程序设计思想也是面向切面软件开发的基础。
简介
面向切面的程序设计将代码逻辑切分为不同的模块(即关注点,一段特定的逻辑功能)。几乎所有的编程思想都涉及代码功能的分类,将各个关注点(Concern)封装成独立的抽象模块(如函数、过程、模块、类以及方法等),后者又可供进一步实现、封装和重写。部分关注点“横切”程序代码中的数个模块,即在多个模块中都有出现,它们即被称作横切关注点(Cross-cutting concerns, Horizontal concerns)。
日志功能即是横切关注点的一个典型案例,因为日志功能往往横跨系统中的每个业务模块,即“横切”所有有日志需求的类及方法体。而对于一个信用卡应用程序来说,存款、取款、帐单管理是它的核心关注点,日志和持久化将成为横切整个对象结构的横切关注点。
切面的概念源于对面向对象的程序设计和计算反射的融合。面向切面编程语言拥有很多类似于元对象协议的功能,但有更多的限制。切面相关的编程概念包括主题、混入和委托。使用面向切面思想的其他方式有复合过滤器和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称之为通知,并且可以在连接点之前、之后和周围运行。一些实现还支持在一个切面中定义另一个类上的一个方法。
连接点模型可以基于暴露的连接点、如何规定连接点、在连接点上允许的操作,和可以表达的结构性增强来进行比较。
AspectJ的连接点模型
所有有效的Java程序也是有效的AspectJ程序,但是AspectJ容许编程者定义叫切面的特殊构造。切面包含一些对于标准类不能获得到的实体。它们是扩展方法、切点和通知。
扩展方法允许编程者从这个切面内向现存的增加方法、字段或接口。下面例子向类Point
增加一个acceptVisitor
方法(参见访问者模式):
aspect VisitAspect {
void Point.acceptVisitor(Visitor v) {
v.visit(this);
}
}
在AspectJ中连接点包括:方法或构造子调用或执行,一个类或对象的初始化,字段读或写访问,异常处理等。它们不包括:循环、super
调用,throw
子句,多个语句等。
切点是通过组合“原始切点指示符”(PCD)来规定的。
“种类”PCD匹配特定种类的连接点(比如方法执行),并且倾向于接受类似Java签名作为输入。一个这种切点如下所示:
execution(* set*(*))
这个切点匹配一个方法执行连接点,如果这个方法名字开始于set
,并且精确的只有一个任何类型的实际参数。
“动态”PCD检查运行时间类型和绑定变量。例如:
this(Point)
这个切点在当前执行对象是类Point
的实例之时匹配。注意一个类的未限定名字可以通过Java的正常类型查找来使用。
“范围”PCD限制连接点的词法作用域。例如:
within(com.company.*)
这个切点匹配在com.company
包中任何类型的任何连接点。*
是一种形式的通配符,它用来匹配具有一个签名的任何东西。
切点可以复合和命名来重新使用。例如:
pointcut set() : execution(* set*(*) ) && this(Point) && within(com.company.*);
这个切点匹配一个方法执行连接点,如果这个方法名字开始于set
,并且this
是在com.company
包中类型Point
的实例。它可以使用名字set()
来提及。
通知规定在(通过切点指定的)一个连接点(之前、之后或周围)运行特定代码(指定如若一个方法中的代码)。AOP运行时间系统,在这个切点匹配一个连接点的时候,自动调用通知。例如:
after() : set() {
Display.update();
}
这在效果上指定了:“如果set()
切点匹配这个连接点,在连接点完成之后,运行代码Display.update()
。”
实现
下列编程语言已经实现了AOP,于语言之内或外部库:
- .NET Framework语言(C# / VB.NET)[1]
- ActionScript[3]
- Ada[4]
- AutoHotkey[5]
- C / C++[6]
- COBOL[7]
- The Cocoa Objective-C框架[8]
- ColdFusion[9]
- Common Lisp[10]
- Delphi[11][12][13]
- Delphi Prism[14]
- e(IEEE 1647)
- Emacs Lisp[15]
- Groovy
- Haskell[16]
- Java[17]
- JavaScript
- Logtalk[18]
- Lua[19]
- make[20]
- Matlab[21]
- ML[22]
- Perl[23]
- PHP[24]
- Prolog[25]
- Python[26]
- Racket[27]
- Ruby[28][29][30]
- Squeak Smalltalk[31][32]
- UML 2.0[33]
- XML[34]
参考文献
- ↑ Numerous: Afterthought , LOOM.NET , Enterprise Library 3.0 Policy Injection Application Block , AspectDNG , DynamicProxy , Compose* , PostSharp , Seasar.NET , DotSpect (.SPECT) , Spring.NET (as part of its functionality), Wicca and Phx.Morph , SetPoint
- ↑ PostSharp
- ↑ Welcome to as3-commons-bytecode. as3commons.org. [5 May 2018].
- ↑ Ada2012 Rationale (PDF). adacore.com. [5 May 2018].
- ↑ Function Hooks. autohotkey.com. [5 May 2018].
- ↑ Several: AspectC++, FeatureC++, AspectC , AspeCt-oriented C , Aspicere
- ↑ Cobble. vub.ac.be. [5 May 2018].[永久失效链接]
- ↑ AspectCocoa. neu.edu. [5 May 2018].
- ↑ ColdSpring Framework: Welcome. 5 November 2005 [5 May 2018].
- ↑ Closer Project: AspectL.. [11 August 2015].
- ↑ infra - Frameworks Integrados para Delphi - Google Project Hosting.
- ↑ meaop - MeSDK: MeObjects, MeRTTI, MeAOP - Delphi AOP(Aspect Oriented Programming), MeRemote, MeService... - Google Project Hosting.
- ↑ Google Project Hosting.
- ↑ RemObjects Cirrus. codegear.com. [5 May 2018].
- ↑ Emacs Advice Functions. gnu.org. [5 May 2018].
- ↑ Monads allow program semantics to be altered by changing the type of the program without altering its code: De Meuter, Wolfgang. Monads As a theoretical basis for AOP. International Workshop on Aspect-Oriented Programming at ECOOP. 1997: 25. CiteSeerX 10.1.1.25.8262 . Tabareau, Nicolas; Figueroa, Ismael; Tanter, Éric. A Typed Monadic Embedding of Aspects. Proceedings of the 12th Annual International Conference on Aspect-oriented Software Development. Aosd '13. March 2013: 171–184. ISBN 9781450317665. S2CID 27256161. doi:10.1145/2451436.2451457. Type classes allow additional capabilities to be added to a type: Sulzmann, Martin; Wang, Meng. Aspect-oriented programming with type classes. Proceedings of the 6th Workshop on Foundations of Aspect-oriented Languages. March 2007: 65–74. ISBN 978-1595936615. S2CID 3253858. doi:10.1145/1233833.1233842..
- ↑ Numerous others: CaesarJ , Compose* , Dynaop , JAC , Google Guice (as part of its functionality), Javassist , JAsCo (and AWED) , JAML , JBoss AOP , LogicAJ , Object Teams , PROSE , The AspectBench Compiler for AspectJ (abc) , Spring framework (as part of its functionality), Seasar, The JMangler Project , InjectJ , GluonJ , Steamloom
- ↑ Using built-in support for categories (which allows the encapsulation of aspect code) and event-driven programming (which allows the definition of before and after event handlers).
- ↑ AspectLua. [11 August 2015].
- ↑ MAKAO, re(verse)-engineering build systems. [11 August 2015].
- ↑ McLab. [11 August 2015].
- ↑ AspectML - Aspect-oriented Functional Programming Language Research. [11 August 2015].
- ↑ Adam Kennedy. Aspect - Aspect-Oriented Programming (AOP) for Perl - metacpan.org. [11 August 2015].
- ↑ Several: PHP-AOP (AOP.io) , Go! AOP framework , PHPaspect , Seasar.PHP , PHP-AOP, Flow , AOP PECL Extension
- ↑ bigzaphod.org is coming soon. www.bigzaphod.org. [5 May 2018].
- ↑ Several: PEAK , Aspyct AOP, Lightweight Python AOP , Logilab's aspect module , Pythius , Spring Python's AOP module , Pytilities' AOP module , aspectlib
- ↑ PLaneT Package Repository : PLaneT > dutchyn > aspectscheme.plt. [11 August 2015].
- ↑ AspectR - Simple aspect-oriented programming in Ruby. [11 August 2015].
- ↑ Dean Wampler. Home. [11 August 2015].
- ↑ gcao/aspector. GitHub. [11 August 2015].
- ↑ AspectS. tu-ilmenau.de. [5 May 2018].
- ↑ MetaclassTalk: Reflection and Meta-Programming in Smalltalk. [11 August 2015].
- ↑ WEAVR. iit.edu. [5 May 2018].
- ↑ aspectxml - An Aspect-Oriented XML Weaving Engine (AXLE) - Google Project Hosting.
站外链接
- Aspect-Oriented Software Development
- Aspect-Oriented Software Development(AOP年会)
- AOSD Wiki (英文维基给AOP的专栏)
- AspectJ (Java的实现)
- [1] 更多有关于类型间成员宣告的资料
- 关于面向侧面的程序设计和AspectJ的系列文章
- The AspectBench Compiler for AspectJ(另一个Java实现)
- 一篇深度讨论AOP与AspectJ的系列文章
- 利用RemObject Taco实现AOP的文章
- Constraint-Specification Aspect Weaver
- 面向侧面对面向对象:该用哪个?何时使用?
- 给Python用的AOP轻量实现
- LOOM.NET
- 面向切面的程序设计(AOP/AOSD)简介