Observer模式在UI的实现里非常常用一个设计模式,通过向父窗体来注册子窗体组,可以实现在父窗体获得事件时,统一调度子窗体的行为。
我们先来看一个简单的观察者模式的实现。在观察者模式中包括两个部分,其一是观察者,其二是受观察者。在整个观察者模式运转体系中,一般只存在一个受观察者,而存在n个观察者。观察者的定义一般通过接口来实现,如下:这里明确定义了观察者接口,其中performAction方法用于实现当观察者被激活以后所操作的业务逻辑。实现当然是非常简单的,下面是受观察者:
- /**
- *
- */
- package com.patterns.observer;
- /**
- * @author Eliotte
- *
- * 2007-12-26
- *
- * 观察者接口
- */
- public interface IObserver {
- /**
- * 观察者响应事件的操作
- *
- * @param strategy
- * 观察者策略
- */
- public void performAction();
- }
- /**
- *
- */
- package com.patterns.observer;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * @author Eliotte
- *
- * 2007-12-26
- *
- * 用于注册0..*个IObserver,事件由此引发并调用
- *
- */
- public abstract class ObserverableHost {
- private List<iobserver></iobserver> observers;
- public ObserverableHost() {
- this.observers = new ArrayList<iobserver></iobserver>();
- }
- /**
- * 注册一个观察者
- *
- * @param observer
- * 观察者实例
- */
- public void attachObserver(IObserver observer) {
- if (observer != null) {
- this.observers.add(observer);
- }
- }
- /**
- * 注销一个观察者
- *
- * @param observer
- * 观察者实力
- */
- public void detachObserver(IObserver observer) {
- if (observer != null) {
- this.observers.remove(observer);
- }
- }
- /**
- * 任何需要的过程就调用这个方法来唤醒观察者
- */
- public void notifyJobs() {
- for (IObserver observer : this.observers) {
- observer.performAction();
- }
- }
- }
受观察者提供了注册(attachObserver)、注销(detachObserver)和调度(notifyJobs)这三个基本的能力来实现观察者模式的基本需求(这是一个典型的推模式)。
在受观察者的派生类中,我们在需要的地方(比如特定的事件出发)调用notifyJobs方法,就能够实现观察者模式的总成调度。当然,这些内容,稍微有设计模式基础的人都应该了解。在观察者模式(推模式)中,受观察者调度了所有的观察者一个固定的方法,相当于我确定知道观察者了解掌握了必要的内容,而相应的,如果采用拉模式,只是把受观察者本身的引用传递到观察者用,由观察者来决定我需要哪些资源。
但是,对于传统的观察者模式,我感觉存在缺陷,或者说它的设计本省存在一定的局限性。我们描述一件事情的发生,是通过一个完整的语法“谁 做了 什么”来表述的。在观察者模式中,假设我们存在一个派生类继承了ObserverableHost,那么他自身将维护一个列表来记录所有观察者,这组观察者在特定事件触发后全部被激活,并作了一件和这个事件相关的事情,并且必须是这件事情,那么,在观察者模式(推模式)中,我们将把一件事情描述为“这些人 做了 这些事情”。我们不能够动态地控制观察者的数量和行为,观察者的行为和数量被绑定在一个固有的方法notifyJobs上。
那么假设我们有这样一个需求,我的受观察者本身可能相应n个事件,我注册了m个观察者,每个事件可能要求这m个观察者中的某k个观察者来做某些动作,如果采用传统的观察者来实现,那么势必要求受观察者来维护多组观察者列表用于不同的事件监听,并且当出现新的事件时,我们不能够通过添加新的类来解决问题,而是很可能要修改原有的代码。为了满足这个需求,我在这里引入了策略模式。
策略模式的根本意图是为事件响应提供一个(或一组中的一个)确定格式的参数,当传入的策略参数不同时,系统将表现不同的行为。
那么不多说,先看代码,我们定义如下策略接口:在策略接口中,要求实现一个方法是performStrategy,这个方法的目的很明确,要求传入一个基准的观察者集合,通过业务逻辑过滤观察者,返回一组符合该策略的观察者集合。策略和事件绑定,也就是说,当触发特定事件时(这里的事件表示满足某个业务判断),这个策略将生效,那么就唤醒特定一组观察者进行工作,这里传入的基准观察者集合通常就是所有可用的观察者集合。
- /**
- *
- */
- package com.patterns.observer;
- import java.util.List;
- /**
- * @author Eliotte
- *
- * 2007-12-26
- *
- * 观察者策略接口
- *
- */
- public interface IObserverStrategy {
- /**
- * 策略验证
- */
- public List<iobserver></iobserver> performStrategy(List<iobserver></iobserver> observers);
- }
那么,为了满足“谁 做了 什么”这个描述,让一切都动起来,我对观察者接口和受观察者基类也做了相应的修改:
- /**
- *
- */
- package com.patterns.observer;
- /**
- * @author Eliotte
- *
- * 2007-12-26
- *
- * 观察者接口
- */
- public interface IObserver {
- /**
- * 观察者响应事件的操作
- *
- * @param strategy
- * 观察者策略
- */
- public void performAction(IObserverStrategy strategy);
- }
- /**
- *
- */
- package com.patterns.observer;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * @author Eliotte
- *
- * 2007-12-26
- *
- * 用于注册0..*个IObserver,事件由此引发并调用
- *
- */
- public abstract class ObserverableHost {
- private List<iobserver></iobserver> observers;
- public ObserverableHost() {
- this.observers = new ArrayList<iobserver></iobserver>();
- }
- /**
- * 注册一个观察者
- *
- * @param observer
- * 观察者实例
- */
- public void attachObserver(IObserver observer) {
- if (observer != null) {
- this.observers.add(observer);
- }
- }
- /**
- * 注销一个观察者
- *
- * @param observer
- * 观察者实力
- */
- public void detachObserver(IObserver observer) {
- if (observer != null) {
- this.observers.remove(observer);
- }
- }
- /**
- * 任何需要的过程就调用这个方法来唤醒观察者
- */
- public void notifyJobs(IObserverStrategy strategy) {
- for (IObserver observer : strategy.performStrategy(this.observers)) {
- observer.performAction(strategy);
- }
- }
- }
受观察者的唤醒加入了对策略的考量,当我们实现一个受观察者之后,就需要针对不同的业务逻辑来实现特定的策略,新增加到策略对以前的程序并不产生修改的影响。
在ObserverableHost.notifyJobs()方法中,我们利用策略对象IObserverStrategy来确定谁来做,事件本身来确认做不做,而在IObserver.performAction()方法中我也同样传入了策略对象,来确定做什么。当然,这里没有写出来的代码就是在观察者中怎么实现做什么,其实很简单,我们只要在IObserver.performAction()方法中加入代码:实现第二个策略:
- /**
- *
- */
- package com.patterns.observer;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * @author Eliotte
- *
- * 2007-12-26
- *
- */
- public class StrategyTwo implements IObserverStrategy {
- /*
- * (non-Javadoc)
- *
- * @see com.patterns.observer.IObserverStrategy#performStrategy(java.util.List)
- */
- public List<iobserver></iobserver> performStrategy(List<iobserver></iobserver> observers) {
- // 返回一些选定的IObserver
- return new ArrayList<iobserver></iobserver>(1);
- }
- }
- /**
- *
- */
- package com.patterns.observer;
- /**
- * @author Eliotte
- *
- * 2007-12-26
- *
- */
- public class ConcreteObserverable extends ObserverableHost {
- /**
- * 构造函数中,我们用内部类来简要描述一个新的观察者的实现和注册
- */
- public ConcreteObserverable() {
- // 这里注册了一个新的观察者,当然通常我们不会这样做
- this.attachObserver(new IObserver() {
- public void performAction(IObserverStrategy strategy) {
- if (StrategyOne.class.isInstance(strategy)) {
- // 操作基于策略1的业务逻辑
- } else if (StrategyTwo.class.isInstance(strategy)) {
- // 操作基于策略2的业务逻辑
- } else {
- // 其他业务逻辑
- }
- }
- });
- }
- public void method1() {
- if (true/* 这里表述某个业务判断 */) {
- // 唤醒基于策略1的观察者
- this.notifyJobs(new StrategyOne());
- } else if (false /* 这里表述了另外一个业务判断 */) {
- // 唤醒基于策略2的观察者
- this.notifyJobs(new StrategyTwo());
- }
- }
- }
至此,包含策略支持的动态观察者模式就实现完成。在后来和同事的讨论中,有关解耦的问题还是存在,但是我想能够尽量保证动态和解耦,有时候是取舍的问题,是否能够采用动态代理来实现,但是可能对于一些简单的ui应用,就显得过于复杂了。
也希望听到任何看到这里的人都回音,能让这些东西做得更好
- if(ConcreteStrategy.class.isInstance(strategy)){
- }else if(/* other strategies */){
- }
那么就足可以实现只增加式的添加观察者行为。为了表述清楚,我还是决定写一段代码出来:创建第一个策略:
- /**
- *
- */
- package com.patterns.observer;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * @author Eliotte
- *
- * 2007-12-26
- *
- */
- public class StrategyOne implements IObserverStrategy {
- /*
- * (non-Javadoc)
- *
- * @see com.patterns.observer.IObserverStrategy#performStrategy(java.util.List)
- */
- public List<iobserver></iobserver> performStrategy(List<iobserver></iobserver> observers) {
- // 返回一些选定的IObserver
- return new ArrayList<iobserver></iobserver>(1);
- }
- }