技术开发 频道

用AspectJ增强设计模式上

    对 Java 语言适配器的分析

    适配器模式在传统的实现中运用得很成功。但是什么让它产生横切呢?是“状态”关注点横切了多个不同的传感器类。如果想协同定位一个包中的适配器类,那么这个模式的 OO 实现会很好地得到模块化。包会成为“适配器模块”。包装术语将阻止传感器了解模式,从而形成更加松散的耦合。不幸的是,实现包装任务的那部分应用程序既需要知道适配器,还需要知道应用适配器的传感器。因此,模式会造成“胶水代码”的位置成为横切。

    现在,让我们来看看 Java 语言适配器是如何在我的评价指标上堆叠起来的:

    易于理解:在包中协同定位的统一命名的 SensorAdapter,使得这个模式的意图清晰。不幸的是,胶水代码的位置可能远在适配器之外。由于胶水代码的区域不是结构化的,所以在试图理解模式的时候会忽略它,或者在试图理解它处理的代码时忽略它。

    您还必须关注对象标识的处理问题。也就是说,如果同一对象包装和未包装的版本同处在一个系统中,那么必须想好是否应当对它们同等对待。

    重用:要重用这个模式,就必须从头开始重新实现该模式。
    维护:在向读取器添加新传感器时,必须添加新的适配器类,并更新包装它们的胶水代码。
    组合:假设想要在另一个模式中包含传感器。由于适配器已经忘记传感器,所以它们不受影响。但这是把双刃剑。新的模式应当把适配版本的传感器当作自己的对象,还是应该将未适配版本的传感器当作自己的对象呢?

    AspectJ 适配器

    像使用其他设计模式一样,适配器的 AspectJ 实现保留了它的同类的意图和概念。这个实现采用类型间声明,这是一个重要的横切类型支持,要比切入点和通知(advice)的启动时间更少。如果需要对静态横切进行回顾,请参阅 参考资料 一节,以获得适当的指示。

    像使用纯 OOP 版本一样,AOP 版本的适配器需要 StatusSensor 接口。但是,AspectJ 版本没有采用独立的包装器类,而是采用 声明父母 的形式,让不同的传感器直接实现 StatusSensor,如下如示:
public aspect SensorAdapter { declare parents : (TemperatureGauge || RadiationDetector) implements StatusSensor; }

    现在传感器应当符合接口。但是它们还没有 实现 接口 (这是 AspectJ 编译器会很高兴指出的一个事实)。要完成模式的实现,必须向方面添加要使每个传感器符合要求的类型间方法声明。下面的代码把 getStatus() 方法添加到 TemperatureGauge 类中:

public String TemperatureGauge.getStatus(){ if(this.readTemperature() > 160){ return "DANGER"; } return "OK"; }

    AspectJ 版本的读取器类看起来与用 Java 语言实现的版本相同,除了不必用胶水代码包装传感器。每个传感器同时又是自己的包装器。

    AspectJ 适配器的分析

    用 AspectJ 实现适配器的关键好处是本地化。整个模式都包含在一个方面中,而不是两个以上的独立适配器和非结构化的“包装”位置。这里是根据我的指标考察的 AspectJ 实现的情况:

    易于理解:没有包装,理解模式只需查看适配器方面即可,这消除了四处查看的需要。没有包装还消除了处理对象标识问题的需要。
    重用:AspectJ 版本与其他版本具有同样的可重用性。
    维护:因为每个新传感器只包括编写一个方法(而不是完整的类),所以扩展 AspectJ 实现应当略微容易些。随着适配器的数量增长或者每个适配要求的逻辑变复杂,可能会发现单一的方面会变得不合理地长。在这种情况下,可以把一个方面拆分成几个方面。拆分方面会损失本地化的好处,但是可以保留其他好处。
    组合:可以很容易地组合多个模式,因为不需要处理包装协调的问题。
    结果是:Java 和 AspectJ 实现在处理传感器类的方式上都做得不错。但是,只有 AspectJ 版本处理了应用程序的其他方面。这是一个主要优势吗?这可能取决于应用程序是否会表现出分析中描述的复杂属性。如果我正对某一个项目使用 AspectJ,那么我肯定会用它实现适配器,虽然我介绍 AspectJ 不仅仅是为了解决这个问题。下一个模式,即修饰器模式,提供了一些更引人注目的优势。

0
相关文章