软件项目实训及课程设计指导——如何在系统架构设计中应用面向切面的设计思想分离横切关注点

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

软件项目实训及课程设计指导——如何在系统架构设计中应用面向切面的设计思想分离横切关注点
1、什么是面向切面编程AOP(Aspect Oriented Programming)技术
所谓的AOP其实是一种编程技术——通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。

读者可能对其中的“Aspect”比较难理解,什么是Aspect?
中文直译Aspect通常是“方面”,更准确的应该为“切面”,但这个名词容易使人混淆或者太抽象。

软件应用系统中的“横切问题”(切面问题)主要是指如何实现对软件应用系统中的如下典型问题的技术实现:事务、安全、日志、并发锁等横切关注。

因为,当软件应用系统变得越来越复杂,其中的这些横切关注点等方面的技术问题如何有效地得以解决,并成为一个比较棘手的问题时,面向切面编程AOP的相关技术就可以很轻松地解决软件应用系统中横切关注点这些棘手问题。

2、为什么要应用面向切面编程AOP技术
面向切面编程AOP技术可以解决传统的面向对象编程OOP(Object Oriented Programming)中不能够很好地解决的横切(CrossCut)方面的问题——比如在应用系统中所经常需要解决的如事务、安全、日志、缓存和并发访问中的锁定等问题都属于应用系统中的“横切”关注方面的问题。

应用面向切面编程AOP的主要目的:
首先,尽量分离软件应用系统中的“技术问题实现”和“业务问题实现”之间的耦合关系,它允许软件系统的开发者能够对横切关注点进行模块化设计——“切面”的意义在于将业务逻辑中复杂问题分离成不同层面,使其实现统一集中的管理。

其次,能够实现分散关注,将软件应用系统中通用的需求功能(如事务、安全、日志、并发锁等)从不相关的业务处理程序类之中分离出来。

这样将能够更好地遵守面向对象设计中所倡导的类设计的“单一职责”原则。

最后,能够实现软件应用系统中的代码重用,因为一旦需求行为发生变化,不必修改很多相关的程序类,只需要修改分离出的共享的程序类。

3、面向对象OOP技术擅长解决纵向方面的问题、但不擅长解决横向方面的问题
因为面向对象OOP允许系统开发人员定义从上到下的关系(纵向)——如继承派生,但并不适合定义从左到右的关系(横向),因此面向对象OOP在实现对公共行为进行建模时,展示了强大的代码重用功能,但利用它对跨越多个程序模块的共性的“行为”进行建
模时,面向对象OOP则显得无能为力。

如下示图中的程序代码示例模拟软件应用系统中的日志处理功能的实现,也就是如果开发人员必须要为多个对象和方法应用相同的事务行为(如模拟示例中的日志功能),在普通的面向对象编程中开发人员需要将同样的代码剪切/粘贴到每一个方法里或者调用封装的功能方法。

软件应用系统中的日志代码往往水平地散布在所有对象层次中——在软件应用系统的控制层、业务层和数据访问层都需要日志功能,并且也与它所散布到的对象(一般为业务处理相关)的核心功能毫无关系。

对于软件应用系统中其它类型的程序代码,如安全性、异常处理和透明的持续性也是如此。

这种散布在软件应用系统各处的无关的代码被称为横切(Cross-Cutting)代码,在面向对象OOP设计中,它将导致大量程序代码的重复(如上示图中的logger.log()模拟代码),而不利于各个模块的重用。

因此需要在软件应用系统的设计和开发实现中“分离关注”,而所谓的“分离关注”就是将某一通用的需求功能从不相关的程序类中分离出来,同时能够使得很多程序类共享该通用的需求实现——因为一旦该实现发生变化,只要修改这个“实现”就可以而不影响其它主功能的实现。

对于“AOP 和Spring AOP技术”等有关的编程实现的细节内容,作者已经在“J2EE
项目实训——Spring框架技术”一书中的第6章“AOP 和Spring AOP技术”和第7章“Spring AOP中的Advice通知”作了比较详细的介绍。

作者在此更多地是从软件系统架构设计的角度介绍如何应用面向切面的主要思想完成系统的架构设计,而不再在代码实现层次重复地介绍面向切面编程技术。

4、面向方面AOP编程提供从另一个角度来考虑程序结构以完善面向对象编程(OOP)
AOP技术利用一种称为“横切”的技术,剖解开封装的对象内部——AOP将程序分解成各个方面或者说关注点,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”。

如下示图说明了面向方面AOP编程技术的实现原理:
也许读者会有疑问,为什么面向方面AOP能够解决横切关注点这类问题?
因为在目前主流的面向方面AOP技术的具体实现中,主要是应用AOP的拦截(Interception)能力,它为软件应用系统的设计和开发实现人员提供了“在任何对象的方法调用前/后加入自定义行为”的能力,这将使得设计和开发人员可以很方便地处理企业应用中的横切关注点方面的问题。

而AOP的拦截能力在目前支持或者提供AOP技术实现的应用平台中一般都是“拦截器”组件的方式提供给软件应用系统的设计和开发人员去应用AOP技术。

比如Struts2 MVC 框架中所提供的拦截器组件、J2EE Web组件技术中的Filter(过滤器)组件其实就是这些平台或者框架为软件应用系统设计和开发人员提供的面向方面AOP技术的具体实现。

如上示图所示,在软件应用系统中直接调用代码段与采用拦截器相比唯一不同的是:如果不是用拦截器,代码中需要显示通过代码来调用目标方法。

但在使用拦截器的情况下,则由系统平台或者应用框架自动完成该方法的调用。

通过这种对比不难发现,拦截器的使用优势在于提供了更高层次的解耦,目标程序代码无需手动调用目标方法。

5、面向对象OOP与面向方面AOP应该相互配合,而不是相互排斥
读者在从事软件应用系统的设计和开发实现中,一定要明确面向对象OOP与面向方面AOP应该是相互配合,而不是相互排斥的。

因为面向对象OOP的程序设计的手段是继承、封装和多态性,而面向方面AOP的程序设计的组件是通知/监听器(advice/interceptor)、
引入(introduction)、元数据(metadata)和切入点(pointcut)。

面向方面AOP和面向对象OOP在软件应用系统设计和开发实现中的应用方面的不同点:面向方面AOP是针对具体业务领域中的“技术逻辑”的实现;而面向对象OOP针对业务对象及其关系、业务逻辑的处理。

6、面向方面AOP实际是对GoF设计模式的进一步的扩展
(1)设计模式所追求的是降低程序代码之间的耦合度
设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,增加程序的灵活性和可重用性。

面向方面AOP实际上就是设计模式所追求的目标的一种实现或者说面向方面AOP 实际是GoF设计模式的延续——分离“系统核心”和“外围功能”的各自实现。

(2)面向对象OOP设计的主要问题
它本质是静态和封闭的。

OOP静态的特性导致软件系统设计和开发人员很难达到动态地添加新的功能方法,而OOP封闭的特性同样也导致软件应用系统的任何需求的细微变化都可能需要对原有的功能实现程序类继续扩展、修改和完善,从而对软件应用系统的开发进度造成重大影响或者带来项目延期交付的风险。

(3)应用设计模式进一步完善面向对象OOP设计
在早期的面向对象OOP设计中解决上述问题的主要技术实现策略是利用设计模式进一步完善面向对象OOP,软件系统设计和开发人员在解决面向对象OOP所面临的问题一个常用的方法是应用设计模式。

因为应用设计模式所体现出的优点——设计出灵活、可扩展、可重用的类库、组件,乃至于整个软件应用系统的系统架构,比如在GOF设计模式中提供“装饰器模式”来达到动态地添加新的功能方法的应用效果。

应用设计模式来解决上述特定的设计问题时,将使面向对象OOP设计更灵活、优雅,最终复用性更好。

软件系统设计和开发人员可以充分地应用各种设计模式的具体实现,从而最大程度的利用面向对象的特性,诸如利用继承、多态,对责任进行分离、对依赖进行倒置,面向抽象和面向接口,最终设计出灵活、可扩展、可重用的类库、组件,乃至于整个系统的架构;在软件应用系统设计的过程中,通过各种设计模式体现了对象的行为,暴露的接口,对象间关系,以及对象分别在不同层次中表现出来的形态。

(4)应用设计模式同样所面临的问题
然而鉴于对象封装的特殊性,“设计模式”的触角始终在接口与抽象中大做文章,而对于对象内部则无能为力。

比如在GOF中强调“面向接口”编程也就是希望我们的系统能够有更好的灵活性和可扩展性---分离“变化”和“不变”部分,这样在一定的程度上能够
“适应变化”。

但是,软件系统设计和开发人员希望能够动态地调整对象的内部结构!同时也能够对对象中的方法执行过程能够控制——比如,能够拦截某方法,从而允许在方法执行之前或者执行以后,能够做点其它的事情!——面向对象OOP的“静态”特性很难达到此目的!(5)面向方面AOP实际是对GoF设计模式的进一步的扩展
设计模式所追求的是降低代码之间的耦合度——设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,增加程序的灵活性和可重用性;AOP实际上就是设计模式所追求的目标的一种实现或者说AOP实际是GoF设计模式的延续——分离“系统核心”和“外围功能”的各自实现。

7、面向切面的系统架构设计是对面向对象系统架构设计的进一步扩展和完善
(1)面向对象的系统架构设计方法更擅长解决“纵向”和“核心和外围”关系的问题面向对象的系统架构设计方法基于对象之间存在有一定的相互关系的指导思想,对软件应用系统进行各个层次的“封装”和“隔离”,并产生出各个相关联的功能模块。

并辅助于消息的交互机制来模拟应用系统所要解决的问题领域中真实的实体的工作状态。

因此,面向对象的系统架构设计方法在解决软件应用系统中具有一定关系(如纵向继承、横向依赖和关联、内外组合)的问题时,显示出了其强大的能力。

(2)面向切面系统架构设计方法擅长解决有“横跨”关系的问题
在软件应用系统的体系架构设计中,各个功能模块之间不仅存在有纵向继承、横向依赖和关联、内外组合等形式的关系,也还可能会出现某个功能模块“横跨”或者“散落”在软件应用系统中多个其他功能模块的状况——也就是在软件系统中的多个不同的功能模块中都“渗透”有某个相同的功能模块的代码。

比如软件应用系统中的“安全功能”模块,不仅需要在各个业务功能模块(控制和授权)中出现,而且也需要在软件应用系统的表示层功能模块(身份验证)中出现——如果没有对页面的URL地址进行访问权限的控制,用户只要输入该页面的URL地址就能进入到Web应用系统中的任何功能页面;对“交易日志”等模块,同样也存在类似的应用状况和要求。

因为,对于软件应用系统中的“交易日志”记录功能模块,不仅需要在各个业务功能模块中出现,而且也需要在软件应用系统的持久层中的功能模块中出现。

请见下图所示的“交易日志”记录功能模块的功能需求图示。

对于这些跨越多个系统功能模块的“共同功能行为”如何实现“封装”和“隔离”?如果继续沿用面向对象OOP的系统架构设计方法将不可避免地导致“共同功能行为”的实现代码重复地出现在软件应用系统的不同功能模块中——如果应用继承机制进行功能扩展,当父类的程序代码发生变化被修改后,所有依赖于该父类的各个子类的程序代码也都有可能要修改和重新进行功能测试。

当然,软件应用系统的设计人员可以应用代理设计模式和Java中的反射等技术改善这种重复代码实现的状况,但这并不是根本的解决方法,而且代理和反射的技术实现是比较复杂的。

此时,软件应用系统的设计人员应该应用面向切面AOP的设计思想实现“封装”和“隔离”共同功能行为的程序模块。

(3)面向切面系统架构设计是对面向对象系统架构设计的进一步扩展和完善正是由于软件应用系统中的各个功能模块在纵、横两个维度上都可能存在一定的关系,因此软件应用系统的设计人员在软件应用系统的系统架构设计中不能仅仅将关注点停留在软件应用系统的纵向和内外的“封装”和“隔离”方面,也还要关注横向跨越形式的功能
模块的“封装”和“隔离”问题的解决方案的设计。

因此,软件应用系统的设计人员应用面向对象OOP的系统架构设计方法完成软件应用系统中的纵向和内外关系的功能模块的“封装”和“隔离”设计,同时再应用面向切面AOP 的系统架构设计方法完成横跨形式的功能模块的“封装”和“隔离”。

从这一角度来看,面向切面AOP系统架构设计是对面向对象OOP系统架构设计的进一步扩展和完善、并且两者是相互配合和相互补充。

下图所示的UML组件图是对前面的组件图进一步完善后的设计结果的图示,应用面向切面AOP的系统设计思想将软件应用系统中表示层中的“身份验证”和“页面缓存”、业务层中的“控制和授权”、持久层中的数据访问的“日志记录”和“事务控制”等功能模块从原有的软件应用系统功能模块中分离出来以形成独立的功能组件。

相关文档
最新文档