AOP 解决紧密耦合的难题-用静态横切的强大功能建立高度松散的系统
2004-12-30 16:42
459 查看
用静态横切的强大功能建立高度松散的系统
CTO,Vanward Technologies 2004 年 3 月 许多 Java 开发人员已经接受了面向方面编程(AOP)的非强制性风格和灵活性,特别是在用于建立高度松散和可扩展的企业系统时。在本文中,您将看到 AOP 的功能设计概念之一(静态横切)如何把可能是一大堆混乱的紧密耦合的代码转变成一个强大的、可扩展的企业应用程序。 在将商业需求转换成软件功能的快速开发周期中,面向方面是一种可以利用的强有力的设计原理。通过将首要的设计重点从面向对象编程(OOP)的传统化特性转移出来,AOP 和设计原理允许软件架构师用一种和面向对象相当而又互补的方式来考虑设计。 在本文里,您将学习如何实现 AOP 中最没有得到充分利用的特性之一。横切(crosscutting)是一种蕴含强大力量的相对简单的设计和编程技术,尤其是当它被用于建立松散耦合的、可扩展的企业系统时。虽然动态横切(其中对象的运行时行为可以改变)被认为是 AOP 的根基之一,但静态横切却是一种远不为人所知的技术。我将在本文中尝试弥补这个缺憾。我将首先概述动态和静态横切,然后迅速切入一个实现场景来展示后一种技术。您将亲自体会到静态横切是多么方便地克服了如下这个最常见的企业挑战之一:如何在利用第三方代码的同时保持应用程序代码库(codebase)的灵活性。 请注意,尽管我首先简要地从概念上概述面向方面编程,但本文并不是一篇关于 AOP 的介绍。请参阅 参考资料 一节以获得关于该主题的介绍性文章的列表。 AOP 概述 面向对象设计最根本的魅力在于,它能够将真实世界领域中的实体及各自的行为建模为抽象的对象。以面向对象方式设计的系统产生了很多有效的业务对象,比如 Person、 Account、 Order以及 Event。面向对象设计的缺点在于,这样的业务对象会因为混合的属性和与对象最初意图不一致的操作而变得混乱。 通过使设计者运用动态和静态横切,用一种非强制性的整洁和模块化的方法来添加对象行为,面向方面编程有效地解决了这一问题。 什么是横切? 横切 是面向方面编程的专有名词。它指的是在一个给定的编程模型中穿越既定的职责部分(比如日志记录和性能优化)的操作。在横切的世界里,横切有两种类型:动态横切和静态横切。在本文中,尽管我将简要地同时讨论二者,但我主要关注静态横切。 动态横切 动态横切 是通过 切入点 和 连接点 在一个 方面 中创建行为的过程,连接点可以在执行时横向地应用于现有对象。动态横切通常用于帮助向对象层次中的各种方法添加日志记录或身份认证。下面让我们花点时间了解一下动态横切中的一些实际概念: 方面(aspect)类似于 Java 编程语言中的类。方面定义切入点和通知(advice),并由诸如 AspectJ 这样的方面编译器来编译,以便将横切(包括动态的和静态的)织入(interweave)现有的对象中。 一个 连接点(join point) 是程序执行中一个精确执行点,比如类中的一个方法。例如,对象 Foo中的方法 bar()就可以是一个连接点。连接点 是个抽象的概念;不用主动定义一个连接点。 一个 切入点(pointcut) 本质上一个用于捕捉连接点的结构。例如,可以定义一个切入点来捕捉对对象 Foo中的方法 bar()的所有调用。和连接点相反,切入点需要在方面中定义。 通知(advice) 是切入点的可执行代码。一个经常定义的通知是添加日志记录功能,其中切入点捕捉对对象 Foo中的 bar()的每个调用,然后该通知动态地插入一些日志记录功能,比如捕捉 bar()的参数。 这些概念是动态横切的核心,虽然正如我们即将看到的,它们并不全都是静态横切所必需的。请参阅 参考资料 来了解关于动态横切的更多内容。 静态横切 静态横切 和动态横切的区别在于它不修改一个给定对象的执行行为。相反,它允许通过引入附加的方法字段和属性来修改对象的 结构。此外,静态横切可以把扩展和实现附加到对象的基本结构中。 虽然现在还无法谈及静态横切的普遍使用——它看起来是 AOP 的一个相对未被探索(尽管非常具有吸引力)的特性——然而这一技术蕴含的潜力是巨大的。使用静态横切,架构师和设计者能用一种真正面向对象的方法有效地建立复杂系统的模型。静态横切允许您不用创建很深的层次结构,以一种本质上更优雅、更逼真于现实结构的方式,插入跨越整个系统的公共行为。 在本文剩下的篇幅中,我将重点讲解静态横切的技术和应用。 创建静态横切 创建静态横切的语法和动态横切有很大的不同,即没有切入点和通知。给定一个对象(比如下面定义的 Foo),静态横切使得创建新方法、添加附加的构造函数,甚至改变继承层次都变得十分简单。我们将用一个例子来更好地展示静态横切是怎样在一个现有的类中实现的。清单 1 显示了一个简单的没有方面的 Foo。 清单 1. 没有方面的 Foo
清单 2. 向 Foo添加一个新方法
new关键字是必需的,如清单 3 所示。 清单 3. 向 Foo添加一个新的构造函数
declare parents标签。比如,为了变成多线程的, Foo将需要实现 Runnable,或者扩展 Thread。清单 4 显示了用 declare parents标签来改变 Foo的继承层次。 清单 4. 改变 Foo的继承层次
实现场景 企业系统经常被设计来利用第三方的产品和库。为了不把整个结构和所需产品耦合在一起,通常在设计来与外部厂商代码交互的应用中包括进一个抽象层。在插入其他厂商的实现乃至自主开发的代码时,这个抽象层在对系统的一致性产生最小破坏的情况下,为该体系结构提供了高度的灵活性。 在这个实现场景中,设想系统在某一操作发生后,通过各不相同的通讯渠道通知客户。这个例子系统使用了一个 清单 5. 例子 Email 对象
除了建立一个发送电子邮件、传真、短消息等的自定义通讯系统之外,体系结构团队决定整合进一个供应商的产品,该产品能遵循特定的规则,发送基于任意对象的消息。该产品非常灵活,并且通过 XML 提供了一个映射机制,允许将自定义客户端对象映射到与厂商的特定渠道实现。该厂商的系统严重依赖于这一映射文件和 Java 平台的反射能力来与普通 Java 对象协同工作。为了体现灵活性,体系结构团队建立了一个 Sendable接口模型,如清单 6 所示。 清单 6. 例子 Sendable接口
Sendable接口的类图。 图 1. Email 和 Sendable的类图 设计挑战 除了通过不同渠道发送各种格式的消息的能力之外,供应商通过一个已给的接口,提供一个钩子(hook)来允许进行收件人地址验证。供应商的文档表明,实现这个接口的任何对象都将遵循一个预定义的生命周期,它 validateAddress()方法将被调用,并正确地处理相应的结果行为。如果 validateAddress()返回 false,供应商的通讯系统将不再试图进行相应的通讯。清单 7 显示了供应商的 validateAddress()接口。 清单 7. Sendable接口的地址验证
Sendable接口来扩展供应商的 Validatable接口。但是,这一决定将导致对供应商代码的直接依赖和耦合。如果开发团队接下来决定用另一个供应商的工具,就不得不重构代码库,以删除 Sendable接口中的 extends语句和对象层次中已实现的行为。 一个更优雅且根本上更灵活的解决方案就是使用静态横切来对预期对象添加行为。 静态横切带来援助 运用面向方面的原理,该团队可以创建一个方面来声明 Validatable接口;此外,在方面中,体系结构团队将预期的行为编码在 ValidataAddress()方法中。因为 validateAddress()方法,这样代码就更好地消除了耦合。 validatabl e类型的对象!清单 8 显示了结果方面,其中 Validatable接口。 清单 8. Email 可验证方面
您可以利用 JUnit 来证明 EmailValidateAspect确实改变了 Validatable的一个实例;此外,可以通过一个测试案例来断言,如果 toAddress为 null,对 validateAddress()的调用将返回 false。另外,还可以用另一个测试案例来检验:一个非 null的 toAddress将导致 validateAddress()返回 true。 1-2-3,用 JUnit 进行测试 您可以首先创建这样一个结构,它构造带有简单值的 nul)的 toAddress值。 清单 9. JUnit setUp()
estEmailValidateInstanceof()确保实例是 Validatable类型的,如清单 10 所示。 清单 10. JUnit 校验实例
toAddress字段设置为 null,然后检验 validateAddress()将返回 false。 清单 11. JUnit null toAddress 检查
testEmailAddressValidateTrue()测试案例用 validateAddress(),即 toAddress域的值为 ag@ag.com。 清单 12. JUnit 非 null toAddress 检查
体系结构团队想方设法使用 Sendable接口来抽象通讯实现;然而,他们的第一次尝试就好像忽略了这个接口。从静态横切民 Sendable基接口,从而进一步精炼了其策略。 新的方面创建了一个用供应商的 Validatable接口来对 Sendable接口进行的扩展。此外,他们在方面中创建了已实现的行为。这次, validateAddress()方法是为另一个通信对象定义的: Fax,如清单 13 所示。 清单 13. 一个更好的方面
虽然这里的 API 例子是人为的,但它有望证明在企业体系结构中应用静态横切是多么简单。静态横切应用于本文描述的这一类场景(它可以在其中用于非强制性地改变对象的行为甚至定义)尤为有效,不过它还有其他很多用处。譬如,您可以在开发时用静态横切来“EJB 化”POJO(传统的普通 Java 对象);或者您可以在业务对象中用它来利用诸如 Hibernate 的持久框架的生命周期接口(请参阅参考资料)。 静态横切为很多影响企业代码有效性的轻微缺陷提供了优雅的解决方案。通过本文,您已经学习了该技术的基础知识和它最基本的应用之一。请参阅 参考资料 来学习更多关于面向方面编程和其他横切技术的知识。 参考资料 下载本文中用到的源代码。 您可以从 eclipse.org/aspectj 下载 AspectJ 及其相关工具。该网站还包括一个FAQ、邮件列表、精彩文档和关于 AOP 的其他资源的链接,是一个开始进一步研究的好地方。 AspectWerkz 是一个针对 Java 平台的动态、轻量级和高性能的 AOP/AOSD 框架。 Eclipse IDE 特别提供了一个 AspectJ 插件。 要获得关于面向方面软件开发的综合信息资源,请试试 AOSD.net。 JBoss 团队已经创建了一个有趣的 AOP 框架。 Hibernate 是针对 Java 平台的一个强大的、超高性能的对象/关系型持久性和查询服务。 Codehaus一个包含很多有趣的开放源代码项目的大型知识库,其中包括 AspectWerkz 和 Nanning(另外一个针对 Java 平台的 Aspect 实现)。 访问 Developer Bookstore 以获得技术书籍的全面列表,其中包括 Ivan Kiselev 的 Aspect-Oriented Programming with AspectJ (Sams Publishing,2002)和 Ramnivas Laddad 的 AspectJ in Action (Manning Publishing,2003),以及其他的大量 Java 相关的书籍。 在 developerWorks Java 技术专区 可以找到关于 Java 编程各个方面的文章。 也可以从 developerWorks 浏览 Java 技术专区教程主页 ,获得针对 Java 的免费教程的详尽列表。
|
相关文章推荐
- AOP 解决紧密耦合的难题
- AOP 解决紧密耦合的难题
- AOP 解决紧密耦合的难题
- 企业如果需要建立一个功能非常强大的网站,应该选择哪种建站系统呢?
- “SOAP协议、松散耦合系统、紧密耦合系统、UDDI服务、RAD开发”
- 企业如果需要建立一个功能非常强大的网站,应该选择哪种建站系统呢?
- 利用Spring AOP与JAVA注解为系统增加日志功能
- 日志系统实战 AOP静态注入
- 解决Android系统中CSS设置select高度无效的BUG
- 克隆虚拟机系统整个文件快照,然后另起建立该系统,产生的IP地址冲突解决办法
- 使用EF+ASP.NET MVC+Bootstrap开发一个功能强大的问卷调查系统
- VB.net版机房收费系统——VS报表制作及功能实现中的问题及解决办法(好学的代价=Bug)
- DSL,日常脚本语言,以及底层功能强大通用的静态语言
- 模拟select的功能,解决IE高度不兼容的问题
- Dell R720上的系统安装问题的解决办法(关于RAID建立磁盘阵列的技术)
- 【案例实战】餐饮企业分店財务数据分析系统解决方式:系统功能开发
- 秒杀系统分析以及难题解决
- 使用 Microsoft Office 将 Visual Studio .NET 的强大功能引入业务解决方案的建立[转]
- VirtualBoX虚拟机里安装linux系统,在虚拟系统里安装增强功能报错解决方法