zoukankan      html  css  js  c++  java
  • Java_观察者模式(Observable和Observer) -转

    原文地址: Java_观察者模式(Observable和Observer)

    一、观察者模式介绍
        在Java中通过Observable类和Observer接口实现了观察者模式。一个Observer对象监视着一个Observable对象的变化,当Observable对象发生变化时,Observer得到通知,就可以进行相应的工作
        如果画面A是显示数据库里面的数据,而画面B修改了数据库里面的数据,那么这时候画面A就要重新Load。这时候就可以用到观察者模
    二、观察者模式实现方法
        java.util.Observable中有两个方法对Observer特别重要
        ①setChanged()方法
            /**
             * Sets the changed flag for this {@code Observable}. After calling
             * {@code setChanged()}, {@code hasChanged()} will return {@code true}.
             */  
            protected void setChanged() {  
                changed = true;  
            }  

        ②notifyObservers()方法 / notifyObservers(Object data)方法
            /**
             * If {@code hasChanged()} returns {@code true}, calls the {@code update()}
             * method for every observer in the list of observers using null as the
             * argument. Afterwards, calls {@code clearChanged()}.
             * <p>
             * Equivalent to calling {@code notifyObservers(null)}.
             */  
            public void notifyObservers() {  
                notifyObservers(null);  
            }  
              
            /**
             * If {@code hasChanged()} returns {@code true}, calls the {@code update()}
             * method for every Observer in the list of observers using the specified
             * argument. Afterwards calls {@code clearChanged()}.
             *
             * @param data
             *            the argument passed to {@code update()}.
             */  
            @SuppressWarnings("unchecked")  
            public void notifyObservers(Object data) {  
                int size = 0;  
                Observer[] arrays = null;  
                synchronized (this) {  
                    if (hasChanged()) {  
                        clearChanged();  
                        size = observers.size();  
                        arrays = new Observer[size];  
                        observers.toArray(arrays);  
                    }  
                }  
                if (arrays != null) {  
                    for (Observer observer : arrays) {  
                        observer.update(this, data);  
                    }  
                }  
            }  
        以上两个方法十分重要
        setChanged()方法 ——
            用来设置一个内部标志位注明数据发生了变化
        notifyObservers()方法 / notifyObservers(Object data)方法 ——
            通知所有的Observer数据发生了变化,这时所有的Observer会自动调用复写好的update(Observable observable, Object data)方法来做一些处理(比如说画面数据的更新)。
            我们可以看到通知Observer有两个方法,一个无参,一个有参。那么这个参数有什么作用呢?
            其中一个作用:现在我不想通知所有的Observer,而只想其中一个指定的Observer做一些处理,那么就可以传一个参数作为ID,然后在所有的Observer中判断,每个Observer判断只有接收到底参数ID是属于自己的才做一些处理。
            当然参数还有其他作用,我只是举了个例子。
        下面举个例子加以说明:
            import java.util.Observable;    
            /**
             * 被观察者类
             */      
            public class SimpleObservable extends Observable    
            {    
               private int data = 0;
               
               public int getData(){     
                   return data;    
               }    
                  
               public void setData(int i){    
                   if(this.data != i) {   
                      this.data = i;   
                      setChanged();    
              
                      //只有在setChange()被调用后,notifyObservers()才会去调用update(),否则什么都不干。  
                      notifyObservers();      
                   }    
               }    
            }    

        上面这个类是一个被观察者类,它继承了Observable类,表示这个类是可以被观察的。
        然后在setData()方法里面,也就是数据改变的地方,来调用Observable类的setChanged()方法和notifyObservers()方法,表示数据已改变并通知所有的Observer调用它们的update()方法做一些处理。
        注意:只有在setChange()被调用后,notifyObservers()才会去调用update(),否则什么都不干。
              /**
             * 观察者类
             */        
            public class SimpleObserver implements Observer    
            {    
               public SimpleObserver(SimpleObservable simpleObservable){    
                  simpleObservable.addObserver(this );    
               }    
                  
               public void update(Observable observable ,Object data){  // data为任意对象,用于传递参数  
                  System.out.println(“Data has changed to” + (SimpleObservable)observable.getData());    
               }    
            }   

        通过生成被观察者(SimpleObservable类)的实例,来调用addObserver(this)方法让观察者(SimpleObserver类)达到观察被观察者(SimpleObservable类)的目的。
        然后还要复写update()方法,做数据改变后的一些处理。
        下面可以写一个简单的测试类来测试一下
            public class SimpleTest    
            {    
               public static void main(String[] args){    
                  SimpleObservable doc = new SimpleObservable ();    
                  SimpleObserver view = new SimpleObserver (doc);    
                  doc.setData(1);    
                  doc.setData(2);    
                  doc.setData(2);    
                  doc.setData(3);     
               }    
            }   
        运行结果如下
        [plain] view plain copy
            Data has changed to 1   
            Data has changed to 2  //第二次setData(2)时由于没有setChange,所以update没被调用  
            Data has changed to 3  
        下面介绍一个Observable类的其他一些属性和方法
        属性 ——
            // observers是一个List,保存着所有要通知的observer。      
            List<Observer> observers = new ArrayList<Observer>();  
            // changed是一个boolean型标志位,标志着数据是否改变了。  
            boolean changed = false;  

        方法 ——
            // 添加一个Observer到列表observers中  
            public void addObserver(Observer observer) {  
                if (observer == null) {  
                    throw new NullPointerException();  
                }  
                synchronized (this) {  
                    if (!observers.contains(observer))  
                        observers.add(observer);  
                }  
            }  
              
            // 从列表observers中删除一个observer  
              
            public synchronized void deleteObserver(Observer observer) {  
                observers.remove(observer);  
            }  
              
            // 清空列表observers  
            public synchronized void deleteObservers() {  
                observers.clear();  
            }  
              
            // 返回列表observers中observer的个数  
              
            public int countObservers() {  
                return observers.size();  
            }  
              
              
            // 重置数据改变标志位为未改变  
            protected void clearChanged() {   
            changed = false;  
            }  
              
            // 将数据改变标志位设置为改变  
              
            protected void setChanged() {   
                changed = true;  
            }  
              
              
            // 判断标志位的值  
            public boolean hasChanged() {   
                return changed;  
            }  
              
            // 通知所有observer(无参)  
            public void notifyObservers() {  
                notifyObservers(null);  
            }  
            // 通知所有observer(有参)  
            @SuppressWarnings("unchecked")  
            public void notifyObservers(Object data) {   
                int size = 0;   
                Observer[] arrays = null;   
                synchronized (this) {   
                    if (hasChanged()) {   
                        clearChanged();   
                        size = observers.size();  
                        arrays = new Observer[size];   
                        observers.toArray(arrays);   
                    }   
                }   
                if (arrays != null) {   
                    for (Observer observer : arrays) {   
                        observer.update(this, data);   
                    }   
                }  
            }  
        注意:在Observer对象销毁前一定要用deleteObserver将其从列表中删除,也就是在onDestroy()方法中调用deleteObserver()方法。
        不然因为还存在对象引用的关系,Observer对象不会被垃圾收集,造成内存泄漏,并且已死的Observer仍会被通知到,有可能造成意料外的错误,而且随着列表越来越大,notifyObservers操作也会越来越慢。

  • 相关阅读:
    454 Authentication failed, please open smtp flag first!
    zabbix 调用的发邮件脚本
    Apache Shiro 标签方式授权
    Realm [realm.ShiroDbRealm@15408475] does not support authentication token
    简单的zabbix agent自动安装脚本
    创建IPC端口失败:拒绝访问
    如何对报表的参数控件赋值
    如何对报表的参数控件赋值
    Socket 通信原理(Android客户端和服务器以TCP&&UDP方式互通)
    mysql 执行计划走分区
  • 原文地址:https://www.cnblogs.com/robertsun/p/5212360.html
Copyright © 2011-2022 走看看