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操作也会越来越慢。

  • 相关阅读:
    LeetCode120 Triangle
    LeetCode119 Pascal's Triangle II
    LeetCode118 Pascal's Triangle
    LeetCode115 Distinct Subsequences
    LeetCode114 Flatten Binary Tree to Linked List
    LeetCode113 Path Sum II
    LeetCode112 Path Sum
    LeetCode111 Minimum Depth of Binary Tree
    Windows下搭建PHP开发环境-WEB服务器
    如何发布可用于azure的镜像文件
  • 原文地址:https://www.cnblogs.com/robertsun/p/5212360.html
Copyright © 2011-2022 走看看