对于Observer的扩展研究

Observer模式在UI的实现里非常常用一个设计模式,通过向父窗体来注册子窗体组,可以实现在父窗体获得事件时,统一调度子窗体的行为。

我们先来看一个简单的观察者模式的实现。在观察者模式中包括两个部分,其一是观察者,其二是受观察者。在整个观察者模式运转体系中,一般只存在一个受观察者,而存在n个观察者。观察者的定义一般通过接口来实现,如下:这里明确定义了观察者接口,其中performAction方法用于实现当观察者被激活以后所操作的业务逻辑。实现当然是非常简单的,下面是受观察者:

java 代码
  1. /**  
  2.  *   
  3.  */  
  4. package com.patterns.observer;   
  5.   
  6. /**  
  7.  * @author Eliotte  
  8.  *   
  9.  * 2007-12-26  
  10.  *   
  11.  * 观察者接口  
  12.  */  
  13. public interface IObserver {   
  14.   
  15.     /**  
  16.      * 观察者响应事件的操作  
  17.      *   
  18.      * @param strategy  
  19.      *            观察者策略  
  20.      */  
  21.     public void performAction();   
  22. }   

 

java 代码
  1. /**  
  2.  *   
  3.  */  
  4. package com.patterns.observer;   
  5.   
  6. import java.util.ArrayList;   
  7. import java.util.List;   
  8.   
  9. /**  
  10.  * @author Eliotte  
  11.  *   
  12.  * 2007-12-26  
  13.  *   
  14.  * 用于注册0..*个IObserver,事件由此引发并调用  
  15.  *   
  16.  */  
  17. public abstract class ObserverableHost {   
  18.     private List<iobserver></iobserver> observers;   
  19.   
  20.     public ObserverableHost() {   
  21.         this.observers = new ArrayList<iobserver></iobserver>();   
  22.     }   
  23.   
  24.     /**  
  25.      * 注册一个观察者  
  26.      *   
  27.      * @param observer  
  28.      *            观察者实例  
  29.      */  
  30.     public void attachObserver(IObserver observer) {   
  31.         if (observer != null) {   
  32.             this.observers.add(observer);   
  33.         }   
  34.     }   
  35.   
  36.     /**  
  37.      * 注销一个观察者  
  38.      *   
  39.      * @param observer  
  40.      *            观察者实力  
  41.      */  
  42.     public void detachObserver(IObserver observer) {   
  43.         if (observer != null) {   
  44.             this.observers.remove(observer);   
  45.         }   
  46.     }   
  47.   
  48.     /**  
  49.      * 任何需要的过程就调用这个方法来唤醒观察者  
  50.      */  
  51.     public void notifyJobs() {   
  52.         for (IObserver observer : this.observers) {   
  53.             observer.performAction();   
  54.         }   
  55.     }   
  56. }   

受观察者提供了注册(attachObserver)、注销(detachObserver)和调度(notifyJobs)这三个基本的能力来实现观察者模式的基本需求(这是一个典型的推模式)。

在受观察者的派生类中,我们在需要的地方(比如特定的事件出发)调用notifyJobs方法,就能够实现观察者模式的总成调度。当然,这些内容,稍微有设计模式基础的人都应该了解。在观察者模式(推模式)中,受观察者调度了所有的观察者一个固定的方法,相当于我确定知道观察者了解掌握了必要的内容,而相应的,如果采用拉模式,只是把受观察者本身的引用传递到观察者用,由观察者来决定我需要哪些资源。

但是,对于传统的观察者模式,我感觉存在缺陷,或者说它的设计本省存在一定的局限性。我们描述一件事情的发生,是通过一个完整的语法“谁 做了 什么”来表述的。在观察者模式中,假设我们存在一个派生类继承了ObserverableHost,那么他自身将维护一个列表来记录所有观察者,这组观察者在特定事件触发后全部被激活,并作了一件和这个事件相关的事情,并且必须是这件事情,那么,在观察者模式(推模式)中,我们将把一件事情描述为“这些人 做了 这些事情”。我们不能够动态地控制观察者的数量和行为,观察者的行为和数量被绑定在一个固有的方法notifyJobs上。

那么假设我们有这样一个需求,我的受观察者本身可能相应n个事件,我注册了m个观察者,每个事件可能要求这m个观察者中的某k个观察者来做某些动作,如果采用传统的观察者来实现,那么势必要求受观察者来维护多组观察者列表用于不同的事件监听,并且当出现新的事件时,我们不能够通过添加新的类来解决问题,而是很可能要修改原有的代码。为了满足这个需求,我在这里引入了策略模式。

策略模式的根本意图是为事件响应提供一个(或一组中的一个)确定格式的参数,当传入的策略参数不同时,系统将表现不同的行为。

那么不多说,先看代码,我们定义如下策略接口:在策略接口中,要求实现一个方法是performStrategy,这个方法的目的很明确,要求传入一个基准的观察者集合,通过业务逻辑过滤观察者,返回一组符合该策略的观察者集合。策略和事件绑定,也就是说,当触发特定事件时(这里的事件表示满足某个业务判断),这个策略将生效,那么就唤醒特定一组观察者进行工作,这里传入的基准观察者集合通常就是所有可用的观察者集合。

java 代码
  1. /**  
  2.  *   
  3.  */  
  4. package com.patterns.observer;   
  5.   
  6. import java.util.List;   
  7.   
  8. /**  
  9.  * @author Eliotte  
  10.  *   
  11.  * 2007-12-26  
  12.  *   
  13.  * 观察者策略接口  
  14.  *   
  15.  */  
  16. public interface IObserverStrategy {   
  17.     /**  
  18.      * 策略验证  
  19.      */  
  20.     public List<iobserver></iobserver> performStrategy(List<iobserver></iobserver> observers);   
  21. }   

 

那么,为了满足“谁 做了 什么”这个描述,让一切都动起来,我对观察者接口和受观察者基类也做了相应的修改:

java 代码
  1. /**  
  2.  *   
  3.  */  
  4. package com.patterns.observer;   
  5.   
  6. /**  
  7.  * @author Eliotte  
  8.  *   
  9.  * 2007-12-26  
  10.  *   
  11.  * 观察者接口  
  12.  */  
  13. public interface IObserver {   
  14.   
  15.     /**  
  16.      * 观察者响应事件的操作  
  17.      *   
  18.      * @param strategy  
  19.      *            观察者策略  
  20.      */  
  21.     public void performAction(IObserverStrategy strategy);   
  22. }   
这里,观察者的业务行为加入了策略参数。
java 代码
  1. /**  
  2.  *   
  3.  */  
  4. package com.patterns.observer;   
  5.   
  6. import java.util.ArrayList;   
  7. import java.util.List;   
  8.   
  9. /**  
  10.  * @author Eliotte  
  11.  *   
  12.  * 2007-12-26  
  13.  *   
  14.  * 用于注册0..*个IObserver,事件由此引发并调用  
  15.  *   
  16.  */  
  17. public abstract class ObserverableHost {   
  18.     private List<iobserver></iobserver> observers;   
  19.   
  20.     public ObserverableHost() {   
  21.         this.observers = new ArrayList<iobserver></iobserver>();   
  22.     }   
  23.   
  24.     /**  
  25.      * 注册一个观察者  
  26.      *   
  27.      * @param observer  
  28.      *            观察者实例  
  29.      */  
  30.     public void attachObserver(IObserver observer) {   
  31.         if (observer != null) {   
  32.             this.observers.add(observer);   
  33.         }   
  34.     }   
  35.   
  36.     /**  
  37.      * 注销一个观察者  
  38.      *   
  39.      * @param observer  
  40.      *            观察者实力  
  41.      */  
  42.     public void detachObserver(IObserver observer) {   
  43.         if (observer != null) {   
  44.             this.observers.remove(observer);   
  45.         }   
  46.     }   
  47.   
  48.     /**  
  49.      * 任何需要的过程就调用这个方法来唤醒观察者  
  50.      */  
  51.     public void notifyJobs(IObserverStrategy strategy) {   
  52.         for (IObserver observer : strategy.performStrategy(this.observers)) {   
  53.             observer.performAction(strategy);   
  54.         }   
  55.     }   
  56. }   

受观察者的唤醒加入了对策略的考量,当我们实现一个受观察者之后,就需要针对不同的业务逻辑来实现特定的策略,新增加到策略对以前的程序并不产生修改的影响。

在ObserverableHost.notifyJobs()方法中,我们利用策略对象IObserverStrategy来确定谁来做,事件本身来确认做不做,而在IObserver.performAction()方法中我也同样传入了策略对象,来确定做什么。当然,这里没有写出来的代码就是在观察者中怎么实现做什么,其实很简单,我们只要在IObserver.performAction()方法中加入代码:实现第二个策略:

java 代码
  1. /**  
  2.  *   
  3.  */  
  4. package com.patterns.observer;   
  5.   
  6. import java.util.ArrayList;   
  7. import java.util.List;   
  8.   
  9. /**  
  10.  * @author Eliotte  
  11.  *   
  12.  * 2007-12-26  
  13.  *   
  14.  */  
  15. public class StrategyTwo implements IObserverStrategy {   
  16.   
  17.     /*  
  18.      * (non-Javadoc)  
  19.      *   
  20.      * @see com.patterns.observer.IObserverStrategy#performStrategy(java.util.List)  
  21.      */  
  22.     public List<iobserver></iobserver> performStrategy(List<iobserver></iobserver> observers) {   
  23.         // 返回一些选定的IObserver   
  24.         return new ArrayList<iobserver></iobserver>(1);   
  25.     }   
  26.   
  27. }   
这个时候我们实现一个受观察者,并在受观察者注册一个简单的观察者来描述基于策略的多边的业务逻辑的操作:
java 代码
  1. /**  
  2.  *   
  3.  */  
  4. package com.patterns.observer;   
  5.   
  6. /**  
  7.  * @author Eliotte  
  8.  *   
  9.  * 2007-12-26  
  10.  *   
  11.  */  
  12. public class ConcreteObserverable extends ObserverableHost {   
  13.   
  14.     /**  
  15.      * 构造函数中,我们用内部类来简要描述一个新的观察者的实现和注册  
  16.      */  
  17.     public ConcreteObserverable() {   
  18.         // 这里注册了一个新的观察者,当然通常我们不会这样做   
  19.         this.attachObserver(new IObserver() {   
  20.   
  21.             public void performAction(IObserverStrategy strategy) {   
  22.                 if (StrategyOne.class.isInstance(strategy)) {   
  23.                     // 操作基于策略1的业务逻辑   
  24.                 } else if (StrategyTwo.class.isInstance(strategy)) {   
  25.                     // 操作基于策略2的业务逻辑   
  26.                 } else {   
  27.                     // 其他业务逻辑   
  28.                 }   
  29.   
  30.             }   
  31.         });   
  32.     }   
  33.   
  34.     public void method1() {   
  35.         if (true/* 这里表述某个业务判断 */) {   
  36.             // 唤醒基于策略1的观察者   
  37.             this.notifyJobs(new StrategyOne());   
  38.         } else if (false /* 这里表述了另外一个业务判断 */) {   
  39.             // 唤醒基于策略2的观察者   
  40.             this.notifyJobs(new StrategyTwo());   
  41.         }   
  42.     }   
  43.   
  44. }   

至此,包含策略支持的动态观察者模式就实现完成。在后来和同事的讨论中,有关解耦的问题还是存在,但是我想能够尽量保证动态和解耦,有时候是取舍的问题,是否能够采用动态代理来实现,但是可能对于一些简单的ui应用,就显得过于复杂了。

也希望听到任何看到这里的人都回音,能让这些东西做得更好

java 代码
  1. if(ConcreteStrategy.class.isInstance(strategy)){       
  2. }else if(/* other strategies */){       
  3. }  

那么就足可以实现只增加式的添加观察者行为。为了表述清楚,我还是决定写一段代码出来:创建第一个策略:

java 代码
  1. /**  
  2.  *   
  3.  */  
  4. package com.patterns.observer;   
  5.   
  6. import java.util.ArrayList;   
  7. import java.util.List;   
  8.   
  9. /**  
  10.  * @author Eliotte  
  11.  *   
  12.  * 2007-12-26  
  13.  *   
  14.  */  
  15. public class StrategyOne implements IObserverStrategy {   
  16.   
  17.     /*  
  18.      * (non-Javadoc)  
  19.      *   
  20.      * @see com.patterns.observer.IObserverStrategy#performStrategy(java.util.List)  
  21.      */  
  22.     public List<iobserver></iobserver> performStrategy(List<iobserver></iobserver> observers) {   
  23.         // 返回一些选定的IObserver   
  24.         return new ArrayList<iobserver></iobserver>(1);   
  25.     }   
  26.   
  27. }   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值