当前位置:编程学习 > JAVA >>

实用设计模式之观察者模式

1.什么是观察者模式
        观察者模式是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。

2.观察者模式的实现
        虽然在Java中提供了现成的Observer和Observable实现,但由于Observable已经被实现成class,所以当需要将自己的某个业务类实现成可被观察的特性时,往往还是得自己来实现,因此下文不再使用Java中的Observable和Observer类,而是自行实现。

        通常的实现方式是注册-通知-取消注册。代码如下:


[java]
public interface Listener { 
    void onNotify(); 

 
 
public class Subject { 
    private List<Listener> listeners; 
    private Object value; 
     
    public Subject(){ 
        listeners=new ArrayList<Listener>(); 
        value=new Object(); 
    } 
     
    public void registe(Listener listener){ 
        listeners.add(listener); 
    } 
     
    public void unRegiste(Listener listener){ 
        listeners.remove(listener); 
    } 
     
    private void sendNotify(){ 
        for(Listener listener:listeners){ 
            listener.onNotify(); 
        } 
    } 
     
    public Object getValue(){ 
        return value; 
    } 
     
    public void setValue(Object value){ 
        if (!this.value.equals(value)){ 
            this.value=value; 
            sendNotify(); 
        } 
    } 

public interface Listener {
 void onNotify();
}


public class Subject {
 private List<Listener> listeners;
 private Object value;
 
 public Subject(){
  listeners=new ArrayList<Listener>();
  value=new Object();
 }
 
 public void registe(Listener listener){
  listeners.add(listener);
 }
 
 public void unRegiste(Listener listener){
  listeners.remove(listener);
 }
 
 private void sendNotify(){
  for(Listener listener:listeners){
   listener.onNotify();
  }
 }
 
 public Object getValue(){
  return value;
 }
 
 public void setValue(Object value){
  if (!this.value.equals(value)){
   this.value=value;
   sendNotify();
  }
 }
}

 

2.1.容器的选择
        被观察者需要一个容器来保留注册进来的观察者引用,上文的代码中使用了List作为容器,这个容器的选择会影响到整体的实现方案。

        通常选择用一个Array或List容器来存储,这样一方面可以做到有序,另一方面在通知时方便遍历。

        如果不想有重复的观察者引用,则要么在注册时检查是否已经存在于容器中,比如在上文registe()方法中加入contains()的判断,要么就选择不可重复的容器如Set,Map等。这样的容器本身已经包含了对重复的处理,但也意味着在发送通知时的顺序不是注册时的先后顺序。

2.2.通知后的数据获取方式
        也就是常说的‘推’或‘拉’。推方式是说变化的数据随着对观察者的接口调用以参数的方式传递给观察者。拉方式是说对观察者的接口调用只用于通知数据发生了变化这件事情,由观察者自行调用被观察者的getXXX()方法取得感兴趣的数据。前者不管三七二十一把变化就推给观察者了,不管你有用没用;后者只是尽到通知的义务,你对什么数据感兴趣就自己来拿。这个要根据实际的设计情况进行决策。

        上文的代码中使用了拉的方式,当value发生变化时,会通过sendNotify()方法发送通知给Listener,但通知中未携带value的值,而是由Listener一方根据情况调用getValue()方法来拉取变化后的新的value值。

2.3.通知后的取消注册
        通知后的取消在实际应用中也没有上述示例代码这样简单。一个典型的需求就是某个Listener要在onNotify()方法执行的过程中调用unRegiste(this)。对这一需求的满足可以小心的处理sendNotify()方法,也可以通过标识位进行标识,还可以在sendNotify()中不使用原始的容器而是遍历一个副本,无论怎样,这个需求很容易发生,在实现观察者模式时要进行处理。

2.4.其他问题
        如果Subject是时间相关的业务,就要对每一个listener的运行时间加以约束,要能对每一个onNotify的调用时间进行监控并处理,以保持对每一个Listener的时间分配在一个合理的范围内。或者使用异步、多线程方式调起onNotify()。

        如果Subject需要实现按优先级进行通知,那就要在优先级队列管理及通知调度上下功夫了。

3.总结
        观察者模式说得多,用得多,但在实际工作当中,要深入思考而不是完全照搬示例代码,这也是设计模式给我们的,要学会把它变成自己的经验。

 

补充:软件开发 , Java ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,