用AOP对设计模式进行改进

上传人:自*** 文档编号:23126948 上传时间:2017-11-29 格式:DOC 页数:139 大小:655KB
返回 下载 相关 举报
用AOP对设计模式进行改进_第1页
第1页 / 共139页
用AOP对设计模式进行改进_第2页
第2页 / 共139页
用AOP对设计模式进行改进_第3页
第3页 / 共139页
用AOP对设计模式进行改进_第4页
第4页 / 共139页
用AOP对设计模式进行改进_第5页
第5页 / 共139页
点击查看更多>>
资源描述

《用AOP对设计模式进行改进》由会员分享,可在线阅读,更多相关《用AOP对设计模式进行改进(139页珍藏版)》请在金锄头文库上搜索。

1、用 AspectJ 增强设计模式上设计模式长期以来一直是一些经验丰富的开发人员的工具箱的重要组成部分。不幸的是,因为模式可以影响多个类,所以它们也是侵入性的、难于使用(和重用)。本文是 AOPWork 系列的第 3 部分,是一篇由两部分组成的文章,在这篇文章中,Nicholas Lesiecki 将介绍 AOP 是怎样通过根本转变模式实现来解决这一问题的。他研究了三个经典的 Gof 设计模式 (适配器模式、修饰器模式和观察者模式),同时还将讨论使用面向方面技术实现这些模式所带来的实践和设计方面的好处。什么是设计模式?根据 Design Patterns: Elements of Reusabl

2、e Object-Oriented Software: 设计模式系统地命名、促进和解释了解决面向对象系统中重复出现的设计问题的一个通用设计。它描述了问题、解决方案、何时应用该解决方案以及所产生的结果。它还提供了一些实现提示和示例。解决方案是解决问题的对象和类的总体安排。可以定制并实现解决方案,解决具体上下文环境中的问题。 在多年成功地应用模式解决 OO 系统中的问题之后,我发现自己也认同了这个定义。模式是与普通程序员谈论设计的最好方式,它们代表解决“重复出现的设计问题”的最佳实践。所以,当我参加了 Stuart Halloway 的一次访谈时,我感到有点震惊:他为 GoF 提供了另一个头衔:“

3、处理 C+ 中破损事物的修理厂”。他的观点是:在一种语言中以“模式”方式存在的东西,在不同的范式下,可以融入语言本身。接着他给出了 Factories 的示例 该示例在 Java 语言中有用,但在 Objective-C 中却没多大用,后者支持从构造函数中返回子类型。 我思考了很长一段时间,然后我认识到两个方面实际上说的是同一件事之前:设计模式提供了表达那些无法直接在编程语言中表达的概念的词汇表。 那么,AOP 位居何处呢?对于 OOP,我们有 GoF 模式,它提供了处理公共的概念(像观察者和修饰器)的统一方法(尽管有时有点麻烦)。AOP 构建在 OOP 之上,提供了表达横切关注点的直接方式。

4、它认为某些 GoF 模式是关于横切的,可以直接用 AOP 表示。所以您会注意到,对于一些包含许多类的模式,用一个方面就可以表达。有些模式变得更易使用,因为它们可以包含更少代码。有些模式得到了非常好的支持,以致于它们几乎消失不见。其他模式严格绑定到 OOP (例如处理类结构的模式),所以它们在与 AOP 结合使用的时候保持不动。 本文的目的是探索用 AOP (特别是用 AspectJ)进行的模式实现。我选择 GoF 模式,是因为它是一个非常流行和通用的工具。在本文的第 1 部分中,我要设置一些分析模式影响的指标,然后研究适配器和修饰器模式。适配器会演示静态交叉的优势,而修饰器则会暴露它自身是一个

5、正在消失的模式。在 第 2 部分中,我将提供对观察者模式更加深入的研究,这种模式并没有消失,但您会看到在用 AspectJ 实现它时的一些主要好处。第 2 部分将显示 AspectJ 如何使模式转变成可重用的基本方面,从而允许您下载预先构建好的模式库 这是让模式爱好者们兴奋的一大优势。 为什么把 AOP 应用到设计模式? 我前面说过,许多模式都是横切的,当然我不是第一个想到这一点的人。最近有一篇研究论文对 GoF 模式进行了分析,分析发现:在 23 个模式中,有 17 个模式表现出某种程度的横切。(这篇论文是 Jan Hannemann 和 Gregor Kiczales 合著的“Java A

6、spectJ 中的设计模式实现”,请参阅 参考资料 一节,以获取更多细节。) 如果 AOP 承诺可以协助解决横切,那么在设计模式上使用 AOP 有什么好处呢?我先从用通用术语回答这个问题开始,然后设置一个框架,通过它来考察每个设计模式。 在设计模式上使用 AOP 的好处 AOP 第一个关键的好处是把指定设计模式的代码 本地化 的能力。这意味着通常只在一个方面或一对密切关联的方面上就可以实现模式。(这与 Java 语言实现形成对比,在 Java 语言实现中,模式应用程序可以分布在多个类中。)能够在一个地方看到所有代码会带来几个实际的好处。首先,如果模式的所有交互都能在一个地方看到的话,那么阅读代

7、码的人就能更容易地理解模式。其次,如果开发人员需要改变模式的实现,那么他或她就能在一个地方修改模式,而不用在整个系统中追踪模式的片断。最后,开发人员可以用有意义的名称描述封装模式的方面,为以后的维护人员提供有关模式意图的文字线索。例如,可以把方面命名为 SensorAdapter,这表明在传感器上使用的是适配器模式。 AspectJ 模式实现的另一个关键好处就是 遗忘性(obliviousness)。换句话说,在模式中发挥作用的类不必知道这个角色。这个好处直接来自本地化 因为模式是在某一个方面实现本地化的,所以不需要冒犯其参与者。遗忘性让模式参与者更容易理解代码。不仅如此,遗忘性还让模式更容易

8、组合。在 Java 语言实现中,如果类参与到多个模式中,模式的机制会迅速模糊它的核心含义。如果类不知道那些在模式中的参与者,那么可以在其他上下文中重用这些类。在本文的 第 2 部分 中将看到这方面的一个具体示例。 这些好处允许对某些模式实现代码级重用。设计模式的概念和结构一直都是可重用的。如果想实现观察者模式,任何人都可以找出 GoF 的书籍,把模式应用到自己的代码中。但是,如果使用面向方面技术,那么通过下载 ObserverProtocol 方面 (可以在设计模式计划中获得它,请参阅参考资料 一节),就可以避免这个麻烦。除了节省的实现工作之外,代码级重用还允许模式代码和文档进行更紧密的耦合。

9、例如,我可以浏览 ObserverProtocol 的 javadoc,不用另找一本书就可以理解它的意图和结构。 分析框架 每个模式的描述都跟着一个公共结构。我将从一个示例问题开始介绍,提供对这个模式的通用描述。然后我会描述如何实现这个模式,先使用 Java 语言实现它,然后使用 AspectJ 语言实现它。在每个实现后面,我都会描述是什么造成了模式的横切,以及这个版本的模式在理解、维护、重用和编排代码的时候有什么效果。 适配器模式 我要详细考虑的第一个模式就是适配器模式。适配器模式完全是关于兼容性的。这个模式允许类与其他原来由于接口不兼容而无法交互的类进行交互。要在 Java 代码中实现适配

10、器,需要用特殊的适配器类包装目标类,适配器类能把目标类的 API 转换成客户想要的 API,或者转换成能够更容易利用的 API。 设置:提供一个聚合的传感器读取器 假设现在要设计一个航天器,则需要提供一个读取器,读取航天器上所有关键传感器。由于是在扩展现有系统,所以对于每个要访问的传感器而言,都存在方便的 Java 类。例如,可以用以下类访问温度计: public class TemperatureGaugepublic int readTemperature()/accesses sensor internals 可以用以下类访问辐射传感器:public class RadiationDet

11、ector public double getCurrentRadiationLevel()/read radiation somehow 这些传感器类中有一些是其他团队成员编写的,有一些是第三方供应商编写的。现在想要做的是提供一个显示方式,显示每个传感器的状态,这样司令官只要看一眼,就知道飞船是否有问题。以下是所需要功能的一个示例。(实际的显示可能包含闪烁的红灯和高音喇叭,但现在我们只显示文本。) Readout: Sensor 1 status is OK Sensor 2 status is OK Sensor 3 status is BORDERLINE Sensor 4 status

12、 is DANGER! 可以用以下方法实现上述显示: public static void main(String args)RadiationDetector radiationDetector = /find critical detector TemperatureGauge gauge = /get exhaust nozzle gauge List allSensors = new ArrayList();allSensors.add(radiationDetector);allSensors.add(gauge);int count = 1;for (Sensor sensor :

13、 allSensors) /How to read each type of sensor.? 目前为止,一切顺利。但是怎样才能不使用丑陋的 if(sensor instanceof XXX) 检测就能读出每个传感器呢?选项将修改每个传感器类,让它们拥有 getStatus() 方法,以便解释传感器的读取操作,并返回 String,如下所示。 if(this.readTemperature() 160)return DANGER;return OK 这样做会将一些不相关的状态显示代码带到多个类当中,增加它们的复杂性。而且,可能存在一些实际限制 (例如必须重新编译第三方类)。这就是适配器模式发挥

14、作用的地方。 Java 语言的适配器 适配器模式的传统实现方式是:用一个实现了方便的 API 的类来包装每个目标。在这种情况下,要创建一个公共接口,比如 StatusSensor,如下所示: public interface StatusSensorString getStatus(); 有这个公共接口存在,就可以像以下这样实现读取器方法: for (StatusSensor sensor : allSensors) System.out.print(Sensor + count+);System.out.println( status is + sensor.getStatus(); 剩下的

15、惟一挑战就是让每个传感器符合这个接口。适配器类可以实现这一点。在清单 1 中可以看到,每个适配器都以成员变量的形式保存自己包装的传感器,用这个底层的传感器实现 getStatus 方法: 清单 1. 适配器类和客户代码 /Adapter classes public class RadiationAdapter implements StatusSensor private final RadiationDetector underlying;public RadiationAdapter(RadiationDetector radiationDetector) this.underlying

16、 = radiationDetector;public String getStatus() if(underlying.getCurrentRadiationLevel() 1.5)return DANGER;return OK;public class TemperatureAdapter implements StatusSensor /.similar /glue code to wrap each sensor with its adapter. allSensors.add(new RadiationAdapter(radiationDetector);allSensors.add(new TemperatureAdapter(gauge); 清单还显示了在读取器之前用适当的适配器包装每

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号