技术开发 频道

用AspectJ增强设计模式下

    通知观察者

    要实现对观察者的实际更新,ObserverProtocol 需要使用一个循环,这非常类似于它在 Java 语言实现中的使用。但是,它激活通知的方式非常不同。首先,方面定义了一个抽象切入点:

protected abstract pointcut subjectChange(Subject s);

    这个切入点由子方面负责具体化。ObserverProtocol 接着定义了一条通知,该通知对应着 subjectChange() 选中的连接点:

after(Subject subject) returning : subjectChange(subject) { for (Observer observer : getObservers(subject)) { updateObserver(subject, observer); } } protected abstract void updateObserver(Subject subject, Observer observer);

    对于发生变化的主角的每个 Observer,方面都需要调用 updateObserver(),这是它定义的一个抽象方法。通过这种方式,具体的方面可以定义它接收到更新时的意义。

    具体的子方面

    目前,您已经看到 ObserverProtocol 提供的所有内容。要应用这个模式,则需要扩展方面,并对这篇讨论开始提出的 4 个核心的观察者(Observer)模式问题提供具体的答案。下载了 ObserverProtocol 之后,就可以开始创建自己的方面,并声明它扩展了 ObserverProtocol。正如您可能想到的,AspectJ 帮助器会提醒您没有完成方面的定义。必须具体化 subjectChange 切入点,并实现 updateObserver 方法。这些提醒可以充当将模式应用到系统中的指导。

    角色分配

    使用 AspectJ,不用直接修改 Song、Playlist 和 BillingService 类,就可以把角色分配给模式的参与者,如下所示。

declare parents : Playable extends Subject; declare parents : BillingService implements Observer;

    编译器不会强迫您插入这些声明,但是您会发现如果没有它们,就无法使用其余的方面机制,因为 ObserverProtocol 将根据这些标记器接口定义它的切入点和方法。

    触发事件

    这可能是这个方面最重要的部分:具体化 subjectChange 切入点,定义那些操作(构成值得通知的事件)。在这种情况下,切入点指定 play() 方法可以在任何实现 Playable 接口的类上执行(包括 Song 和 Playlist都可以这么做)。切入点也选择执行 Song 上的 showLyrics() 方法:

pointcut titleUse(Playable playable) : this(playable) && ( execution(public void Playable+.play()) || execution(public void Song.showLyrics()) ); public pointcut subjectChange(Subject subject) : titleUse(Playable) && this(subject);

    响应更新

    非常类似于 Java 语言版本,为了响应更新,需要实现更新方法。区别在于,在这里是向方面添加方法,而不是直接向 BillingService 添加,后者不知道自己参与到了模式中:

public void updateObserver(Subject s, Observer o){ BillingService service = (BillingService)o; service.generateChargeFor((Playable)s); }

    启动观察关系

    正如我在前面所提到的,由于方面上存在公共的 addObserver 和 removeObserver,所以可以用编程方式对方面进行配置。要启动对歌曲和播放列表的观察,需要复制 Java 语言的客户实现,并用 ObserverBillingPolicy.aspectOf().addObserver(song, basicBilling) 替代出现 song.addObserver(basicBilling) 的地方。

    但是,为了让模式的存在尽可能保持在不显眼的状态,所以,使用通知自动地开始这种关系是有意义的,如下所示:

//in the concrete aspect //could be injected by a dependency injection framework like Spring //see the Resources section for an excellent blog entry on this topic private BillingService defaultBillingService = new BillingService(); pointcut playableCreation(Subject s) : execution(public Playable+.new(..)) && this(s); after(Subject s) returning : playableCreation(s){ addObserver(s, defaultBillingService); }

    通过使用方面中配置的默认 BillingService,该切入点和通知在创建 Playable 时立即开始计费观察。但是,ObserverProtocol 使得这方面具有灵活性。请进一步想像一下:通知会将辅助计费应用到特定歌曲上,或者检索与系统当前用法有关的计费计划。类似的,可以用通知在歌曲不符合未来计费要求时自动终止关系。

0
相关文章